Shared Library Constructor (rocprofv3 deadlock fix) (#599)

* Moved tests/apps to tests/bin

* Renamed cmake project in tests/bin

* Update samples

- Use ROCPROFILER_DEFAULT_FAIL_REGEX
- tweaks to stdout messages

* Update tests

- Use ROCPROFILER_DEFAULT_FAIL_REGEX

* Add tests/lib

- libraries with HIP code

* Update PTL submodule

- remove atexit delete of thread_id_map

* Update cmake/rocprofiler_options.cmake

- Set ROCPROFILER_DEFAULT_FAIL_REGEX

* Update common lib: env + logging

- improved customization of logging settings
- default to disabling logging to files
- install failure handler for rocprofv3
- set_env support in environment.*

* Add lib/rocprofiler-sdk/shared_library.cpp

- shared library constructor

* Update lib/rocprofiler-sdk-tool/tool.cpp

- destructor thread safety
- convert callback_name_info and buffered_name_info to pointers
- install failure handler for logging

* Add tests/bin/hip-in-libraries

- hip-in-libraries is an exe which uses two shared libraries where each shared library contains HIP kernels
  - used for testing deadlocking within __hipRegisterFatBinary

* Update bin/rocprofv3

- reorganized the env variables
- use exec to launch command
- set ROCPROFILER_LIBRARY_CTOR=1

* Add tests/rocprofv3/tracing-hip-in-libraries

- uses hip-in-libraries exe for exe which uses shared libraries to launch HIP kernels

* Update bin/rocprofv3

- fix counter collection (no exec)

* Update lib/rocprofiler-sdk-tool/tool.cpp

- replace "Kernel-Name" with "Kernel_Name"

* Update lib/rocprofiler-sdk/registration.cpp

Use RTLD_LOCAL instead of RTLD_GLOBAL for env libraries

* Update tests/rocprofv3

- replace "Kernel-Name" with "Kernel_Name"

* Update tests

- vector-ops (bin) stream syncs + runs with 4 queues per device
- improve counter-collection/input1 validation
- rocprofv3/tracing-hip-in-libraries does not do sys-trace
- improved validation script for tracing-hip-in-libraries
- updated dispatch_callback in json-tool.cpp following reworking of prototypes for counter collection

* Update samples/counter_collection

- updated dispatch_callback(s) and record_callback(s) following reworking of prototypes

* Update bin/rocprofv3

- reorganized help menu
- added options for sub-HSA tables
- added --hip-runtime-trace
- changed --hip-trace to include --hip-compiler-trace

* Update lib/rocprofiler-sdk-tool

- improved kernel filtering
- removed arch_vgpr, accum_vgpr, sgpr code (in rocprofiler-sdk)
- fixed issue with counter-collection w/o tracing
- added support for fine grained HSA API tracing
- removed directly linking to HSA-runtime

* Update lib/rocprofiler-sdk/agent.cpp

- rocp_agents != hsa_agents is non-fatal when ROCPROFILER_BUILD_CI=OFF (CMake option)

* GPR (vector and scalar) info in kernel symbol data

- rocprofiler_callback_tracing_code_object_kernel_symbol_register_data_t contains general purpose register info

* Header include order fix

- Include repo headers first
- Third party library headers next
- standard library headers last

* Update dispatch profiling public API

- introduce rocprofiler_profile_counting_dispatch_data_t
- change signature of rocprofiler_profile_counting_dispatch_callback_t and rocprofiler_profile_counting_record_callback_t
- provide rocprofiler_user_data_t pointer in dispatch callback
- provide rocprofiler_user_data_t value (from dispatch cb) in record callback

* Update tests/bin/CMakeLists.txt

- fix add_subdirectory(hip-in-libraries) order

* Update VERSION

- bump to 0.2.0 in prep for AFAR
Tento commit je obsažen v:
Jonathan R. Madsen
2024-03-07 22:21:26 -06:00
odevzdal GitHub
rodič 665c546e65
revize 7b6d3c70bd
85 změnil soubory, kde provedl 2497 přidání a 856 odebrání
-1
Zobrazit soubor
@@ -12,7 +12,6 @@ add_subdirectory(plugins)
target_link_libraries(
rocprofiler-sdk-tool
PRIVATE rocprofiler::rocprofiler-shared-library
rocprofiler::rocprofiler-hsa-runtime
rocprofiler::rocprofiler-headers
rocprofiler::rocprofiler-build-flags
rocprofiler::rocprofiler-memcheck
+16 -13
Zobrazit soubor
@@ -57,19 +57,22 @@ struct config
{
config();
bool demangle = get_env("ROCPROF_DEMANGLE_KERNELS", true);
bool truncate = get_env("ROCPROF_TRUNCATE_KERNELS", false);
bool kernel_trace = get_env("ROCPROF_KERNEL_TRACE", false);
bool hsa_api_trace = get_env("ROCPROF_HSA_API_TRACE", false);
bool marker_api_trace = get_env("ROCPROF_MARKER_API_TRACE", false);
bool memory_copy_trace = get_env("ROCPROF_MEMORY_COPY_TRACE", false);
bool counter_collection = get_env("ROCPROF_COUNTER_COLLECTION", false);
bool hip_api_trace = get_env("ROCPROF_HIP_API_TRACE", false);
bool hip_compiler_api_trace = get_env("ROCPROF_HIP_COMPILER_API_TRACE", false);
bool list_metrics = get_env("ROCPROF_LIST_METRICS", false);
bool list_metrics_output_file = get_env("ROCPROF_OUTPUT_LIST_METRICS_FILE", false);
int mpi_size = get_mpi_size();
int mpi_rank = get_mpi_rank();
bool demangle = get_env("ROCPROF_DEMANGLE_KERNELS", true);
bool truncate = get_env("ROCPROF_TRUNCATE_KERNELS", false);
bool kernel_trace = get_env("ROCPROF_KERNEL_TRACE", false);
bool hsa_core_api_trace = get_env("ROCPROF_HSA_CORE_API_TRACE", false);
bool hsa_amd_ext_api_trace = get_env("ROCPROF_HSA_AMD_EXT_API_TRACE", false);
bool hsa_image_ext_api_trace = get_env("ROCPROF_HSA_IMAGE_EXT_API_TRACE", false);
bool hsa_finalizer_ext_api_trace = get_env("ROCPROF_HSA_FINALIZER_EXT_API_TRACE", false);
bool marker_api_trace = get_env("ROCPROF_MARKER_API_TRACE", false);
bool memory_copy_trace = get_env("ROCPROF_MEMORY_COPY_TRACE", false);
bool counter_collection = get_env("ROCPROF_COUNTER_COLLECTION", false);
bool hip_runtime_api_trace = get_env("ROCPROF_HIP_RUNTIME_API_TRACE", false);
bool hip_compiler_api_trace = get_env("ROCPROF_HIP_COMPILER_API_TRACE", false);
bool list_metrics = get_env("ROCPROF_LIST_METRICS", false);
bool list_metrics_output_file = get_env("ROCPROF_OUTPUT_LIST_METRICS_FILE", false);
int mpi_size = get_mpi_size();
int mpi_rank = get_mpi_rank();
std::string output_path = get_env("ROCPROF_OUTPUT_PATH", fs::current_path().string());
std::string output_file = get_env("ROCPROF_OUTPUT_FILE_NAME", std::to_string(getpid()));
std::vector<std::string> kernel_names = {};
+2 -193
Zobrazit soubor
@@ -22,7 +22,8 @@
#include "helper.hpp"
#include "config.hpp"
#include "rocprofiler-sdk/fwd.h"
#include <rocprofiler-sdk/fwd.h>
#include <glog/logging.h>
@@ -33,198 +34,6 @@
#include <unordered_set>
#include <utility>
namespace
{
using amd_compute_pgm_rsrc_three32_t = uint32_t;
// AMD Compute Program Resource Register Three.
enum amd_compute_gfx9_pgm_rsrc_three_t
{
AMD_HSA_BITS_CREATE_ENUM_ENTRIES(AMD_COMPUTE_PGM_RSRC_THREE_ACCUM_OFFSET, 0, 5),
AMD_HSA_BITS_CREATE_ENUM_ENTRIES(AMD_COMPUTE_PGM_RSRC_THREE_TG_SPLIT, 16, 1)
};
enum amd_compute_gfx10_gfx11_pgm_rsrc_three_t
{
AMD_HSA_BITS_CREATE_ENUM_ENTRIES(AMD_COMPUTE_PGM_RSRC_THREE_SHARED_VGPR_COUNT, 0, 4),
AMD_HSA_BITS_CREATE_ENUM_ENTRIES(AMD_COMPUTE_PGM_RSRC_THREE_INST_PREF_SIZE, 4, 6),
AMD_HSA_BITS_CREATE_ENUM_ENTRIES(AMD_COMPUTE_PGM_RSRC_THREE_TRAP_ON_START, 10, 1),
AMD_HSA_BITS_CREATE_ENUM_ENTRIES(AMD_COMPUTE_PGM_RSRC_THREE_TRAP_ON_END, 11, 1),
AMD_HSA_BITS_CREATE_ENUM_ENTRIES(AMD_COMPUTE_PGM_RSRC_THREE_IMAGE_OP, 31, 1)
};
// Kernel code properties.
enum amd_kernel_code_property_t
{
AMD_HSA_BITS_CREATE_ENUM_ENTRIES(AMD_KERNEL_CODE_PROPERTY_ENABLE_SGPR_PRIVATE_SEGMENT_BUFFER,
0,
1),
AMD_HSA_BITS_CREATE_ENUM_ENTRIES(AMD_KERNEL_CODE_PROPERTY_ENABLE_SGPR_DISPATCH_PTR, 1, 1),
AMD_HSA_BITS_CREATE_ENUM_ENTRIES(AMD_KERNEL_CODE_PROPERTY_ENABLE_SGPR_QUEUE_PTR, 2, 1),
AMD_HSA_BITS_CREATE_ENUM_ENTRIES(AMD_KERNEL_CODE_PROPERTY_ENABLE_SGPR_KERNARG_SEGMENT_PTR,
3,
1),
AMD_HSA_BITS_CREATE_ENUM_ENTRIES(AMD_KERNEL_CODE_PROPERTY_ENABLE_SGPR_DISPATCH_ID, 4, 1),
AMD_HSA_BITS_CREATE_ENUM_ENTRIES(AMD_KERNEL_CODE_PROPERTY_ENABLE_SGPR_FLAT_SCRATCH_INIT, 5, 1),
AMD_HSA_BITS_CREATE_ENUM_ENTRIES(AMD_KERNEL_CODE_PROPERTY_ENABLE_SGPR_PRIVATE_SEGMENT_SIZE,
6,
1),
AMD_HSA_BITS_CREATE_ENUM_ENTRIES(AMD_KERNEL_CODE_PROPERTY_RESERVED0, 7, 3),
AMD_HSA_BITS_CREATE_ENUM_ENTRIES(AMD_KERNEL_CODE_PROPERTY_ENABLE_WAVEFRONT_SIZE32,
10,
1), // GFX10+
AMD_HSA_BITS_CREATE_ENUM_ENTRIES(AMD_KERNEL_CODE_PROPERTY_USES_DYNAMIC_STACK, 11, 1),
AMD_HSA_BITS_CREATE_ENUM_ENTRIES(AMD_KERNEL_CODE_PROPERTY_RESERVED1, 12, 4),
};
std::unordered_map<rocprofiler_address_t, const char*> kernel_descriptor_name_map;
std::mutex kernel_properties_correlation_mutex;
std::unordered_map<uint64_t, rocprofiler_tool_kernel_properties_t>
kernel_properties_correlation_map;
uint32_t
arch_vgpr_count(const std::string_view& name, const kernel_descriptor_t& kernel_code)
{
std::string info_name(name.data(), name.size());
if(strcmp(name.data(), "gfx90a") == 0 || strncmp(name.data(), "gfx94", 5) == 0)
return (AMD_HSA_BITS_GET(kernel_code.compute_pgm_rsrc3,
AMD_COMPUTE_PGM_RSRC_THREE_ACCUM_OFFSET) +
1) *
4;
return (AMD_HSA_BITS_GET(kernel_code.compute_pgm_rsrc1,
AMD_COMPUTE_PGM_RSRC_ONE_GRANULATED_WORKITEM_VGPR_COUNT) +
1) *
(AMD_HSA_BITS_GET(kernel_code.kernel_code_properties,
AMD_KERNEL_CODE_PROPERTY_ENABLE_WAVEFRONT_SIZE32)
? 8
: 4);
}
uint32_t
accum_vgpr_count(const std::string_view& name, const kernel_descriptor_t& kernel_code)
{
std::string info_name(name.data(), name.size());
if(strcmp(info_name.c_str(), "gfx908") == 0) return arch_vgpr_count(name, kernel_code);
if(strcmp(info_name.c_str(), "gfx90a") == 0 || strncmp(info_name.c_str(), "gfx94", 5) == 0)
return (AMD_HSA_BITS_GET(kernel_code.compute_pgm_rsrc1,
AMD_COMPUTE_PGM_RSRC_ONE_GRANULATED_WORKITEM_VGPR_COUNT) +
1) *
8 -
arch_vgpr_count(name, kernel_code);
return 0;
}
uint32_t
sgpr_count(const std::string_view& name, const kernel_descriptor_t& kernel_code)
{
// GFX10 and later always allocate 128 sgprs.
// TODO(srnagara): Recheck the extraction of gfxip from gpu name
const char* name_data = name.data();
const size_t gfxip_label_len = std::min(name.size() - 2, size_t{63});
if(gfxip_label_len > 0 && strnlen(name_data, gfxip_label_len + 1) >= gfxip_label_len)
{
auto gfxip = std::vector<char>{};
gfxip.resize(gfxip_label_len + 1, '\0');
memcpy(gfxip.data(), name_data, gfxip_label_len);
// TODO(srnagara): Check if it is hardcoded
if(std::stoi(&gfxip.at(3)) >= 10) return 128;
return (AMD_HSA_BITS_GET(kernel_code.compute_pgm_rsrc1,
AMD_COMPUTE_PGM_RSRC_ONE_GRANULATED_WAVEFRONT_SGPR_COUNT) /
2 +
1) *
16;
}
return 0;
}
const auto&
GetLoaderTable()
{
static const auto _v = []() {
using hsa_loader_table_t = hsa_ven_amd_loader_1_01_pfn_t;
auto _tbl = hsa_loader_table_t{};
memset(&_tbl, 0, sizeof(hsa_loader_table_t));
hsa_system_get_major_extension_table(
HSA_EXTENSION_AMD_LOADER, 1, sizeof(hsa_loader_table_t), &_tbl);
return _tbl;
}();
return _v;
}
const kernel_descriptor_t*
GetKernelCode(uint64_t kernel_object)
{
const kernel_descriptor_t* kernel_code = nullptr;
if(GetLoaderTable().hsa_ven_amd_loader_query_host_address == nullptr) return kernel_code;
hsa_status_t status = GetLoaderTable().hsa_ven_amd_loader_query_host_address(
reinterpret_cast<const void*>(kernel_object), // NOLINT(performance-no-int-to-ptr)
reinterpret_cast<const void**>(&kernel_code));
if(HSA_STATUS_SUCCESS != status)
{
kernel_code = reinterpret_cast<kernel_descriptor_t*>( // NOLINT(performance-no-int-to-ptr)
kernel_object);
}
return kernel_code;
}
} // namespace
void
SetKernelProperties(uint64_t correlation_id, rocprofiler_tool_kernel_properties_t kernel_properties)
{
std::lock_guard<std::mutex> kernel_properties_correlation_map_lock(
kernel_properties_correlation_mutex);
kernel_properties_correlation_map[correlation_id] = std::move(kernel_properties);
}
rocprofiler_tool_kernel_properties_t
GetKernelProperties(uint64_t correlation_id)
{
std::lock_guard<std::mutex> kernel_properties_correlation_map_lock(
kernel_properties_correlation_mutex);
auto it = kernel_properties_correlation_map.find(correlation_id);
if(it == kernel_properties_correlation_map.end())
{
std::cout << "kernel properties not found" << std::endl;
abort();
}
return it->second;
}
void
populate_kernel_properties_data(rocprofiler_tool_kernel_properties_t* kernel_properties,
const hsa_kernel_dispatch_packet_t* dispatch_packet)
{
const uint64_t kernel_object = dispatch_packet->kernel_object;
const kernel_descriptor_t* kernel_code = GetKernelCode(kernel_object);
uint64_t grid_size =
dispatch_packet->grid_size_x * dispatch_packet->grid_size_y * dispatch_packet->grid_size_z;
if(grid_size > UINT32_MAX) abort();
kernel_properties->grid_size = grid_size;
uint64_t workgroup_size = dispatch_packet->workgroup_size_x *
dispatch_packet->workgroup_size_y * dispatch_packet->workgroup_size_z;
if(workgroup_size > UINT32_MAX) abort();
kernel_properties->workgroup_size = (uint32_t) workgroup_size;
kernel_properties->lds_size = dispatch_packet->group_segment_size;
kernel_properties->scratch_size = dispatch_packet->private_segment_size;
kernel_properties->arch_vgpr_count =
arch_vgpr_count(kernel_properties->gpu_agent.name, *kernel_code);
kernel_properties->accum_vgpr_count =
accum_vgpr_count(kernel_properties->gpu_agent.name, *kernel_code);
kernel_properties->sgpr_count = sgpr_count(kernel_properties->gpu_agent.name, *kernel_code);
kernel_properties->wave_size =
AMD_HSA_BITS_GET(kernel_code->kernel_code_properties,
AMD_KERNEL_CODE_PROPERTY_ENABLE_WAVEFRONT_SIZE32)
? 32
: 64;
kernel_properties->signal_handle = dispatch_packet->completion_signal.handle;
}
rocprofiler_tool_buffer_name_info_t
get_buffer_id_names()
{
-63
Zobrazit soubor
@@ -71,46 +71,6 @@
constexpr size_t BUFFER_SIZE_BYTES = 4096;
constexpr size_t WATERMARK = (BUFFER_SIZE_BYTES / 2);
// This can be different for different architecture
// Lets follow the v1 rocprof
// I will have a kernel id from the rocprofiler
// address the kernel descriptor and access the information
// This works for gfx9 but may not for Navi arch
// Interecept the kernel symbol load build a table for kernel id
// when kenel dispatch callback. Here is the kernel id
// Use the kernel id
typedef struct
{
uint64_t grid_size;
uint64_t workgroup_size;
uint64_t lds_size;
uint64_t scratch_size;
uint64_t arch_vgpr_count;
uint64_t accum_vgpr_count;
uint64_t sgpr_count;
uint64_t wave_size;
uint64_t signal_handle;
uint64_t kernel_object;
rocprofiler_queue_id_t queue_id;
std::string kernel_name;
rocprofiler_agent_t gpu_agent;
uint64_t thread_id;
uint64_t dispatch_index;
} rocprofiler_tool_kernel_properties_t;
struct kernel_descriptor_t
{
uint8_t reserved0[16];
int64_t kernel_code_entry_byte_offset;
uint8_t reserved1[20];
uint32_t compute_pgm_rsrc3;
uint32_t compute_pgm_rsrc1;
uint32_t compute_pgm_rsrc2;
uint16_t kernel_code_properties;
uint8_t reserved2[6];
};
using rocprofiler_tool_buffer_kind_names_t =
std::unordered_map<rocprofiler_buffer_tracing_kind_t, const char*>;
using rocprofiler_tool_buffer_kind_operation_names_t =
@@ -135,29 +95,6 @@ struct rocprofiler_tool_callback_name_info_t
rocprofiler_tool_callback_kind_operation_names_t operation_names = {};
};
// std::vector<std::string>
// GetCounterNames();
void
SetKernelDescriptorName(rocprofiler_address_t kernel_descriptor, const char* name);
void
SetKernelProperties(uint64_t correlation_id,
rocprofiler_tool_kernel_properties_t kernel_properties);
void
SetKernelProperties(uint64_t correlation_id,
rocprofiler_tool_kernel_properties_t kernel_properties);
rocprofiler_tool_kernel_properties_t
GetKernelProperties(uint64_t correlation_id);
const char*
GetKernelDescriptorName(rocprofiler_address_t kernel_descriptor);
void
populate_kernel_properties_data(rocprofiler_tool_kernel_properties_t* kernel_properties,
const hsa_kernel_dispatch_packet_t* dispatch_packet);
rocprofiler_tool_buffer_name_info_t
get_buffer_id_names();
+284 -176
Zobrazit soubor
@@ -33,6 +33,8 @@
#include "lib/common/utility.hpp"
#include <rocprofiler-sdk/agent.h>
#include <rocprofiler-sdk/callback_tracing.h>
#include <rocprofiler-sdk/external_correlation.h>
#include <rocprofiler-sdk/fwd.h>
#include <rocprofiler-sdk/internal_threading.h>
#include <rocprofiler-sdk/marker/api_id.h>
@@ -55,6 +57,21 @@
namespace common = ::rocprofiler::common;
namespace tool = ::rocprofiler::tool;
namespace std
{
template <>
struct hash<rocprofiler_agent_id_t>
{
size_t operator()(rocprofiler_agent_id_t id) const { return id.handle; }
};
} // namespace std
inline bool
operator==(rocprofiler_agent_id_t lhs, rocprofiler_agent_id_t rhs)
{
return (lhs.handle == rhs.handle);
}
namespace
{
constexpr uint32_t lds_block_size = 128 * 4;
@@ -68,16 +85,23 @@ get_dereference(Tp* ptr)
return *CHECK_NOTNULL(ptr);
}
template <typename Tp>
void
add_destructor(Tp*& ptr)
auto
get_destructors_lock()
{
static auto _mutex = std::mutex{};
auto _lk = std::unique_lock<std::mutex>{_mutex};
return std::unique_lock<std::mutex>{_mutex};
}
template <typename Tp>
Tp*&
add_destructor(Tp*& ptr)
{
auto _lk = get_destructors_lock();
destructors->emplace_back([&ptr]() {
delete ptr;
ptr = nullptr;
});
return ptr;
}
#define ADD_DESTRUCTOR(PTR) \
@@ -155,7 +179,7 @@ get_counter_collection_file()
"Process_Id",
"Thread_Id",
"Grid_Size",
"Kernel-Name",
"Kernel_Name",
"Workgroup_Size",
"LDS_Block_Size",
"Scratch_Size",
@@ -255,6 +279,7 @@ get_buffers()
return _v;
}
using rocprofiler_code_object_data_t = rocprofiler_callback_tracing_code_object_load_data_t;
using rocprofiler_kernel_symbol_data_t =
rocprofiler_callback_tracing_code_object_kernel_symbol_register_data_t;
@@ -274,14 +299,46 @@ struct kernel_symbol_data : rocprofiler_kernel_symbol_data_t
std::string truncated_kernel_name = {};
};
template <typename Tp>
Tp*
as_pointer(Tp&& _val)
{
return new Tp{std::forward<Tp>(_val)};
}
using code_object_data_map_t = std::unordered_map<uint64_t, rocprofiler_code_object_data_t>;
using kernel_symbol_data_map_t = std::unordered_map<rocprofiler_kernel_id_t, kernel_symbol_data>;
auto kernel_data = common::Synchronized<kernel_symbol_data_map_t, true>{};
using targeted_kernels_set_t = std::unordered_set<rocprofiler_kernel_id_t>;
using counter_dimension_info_map_t =
std::unordered_map<uint64_t, std::vector<rocprofiler_record_dimension_info_t>>;
std::atomic<uint64_t> dispatch_index{0};
auto counter_dimension_data = common::Synchronized<counter_dimension_info_map_t, true>{};
auto buffered_name_info = get_buffer_id_names();
auto callback_name_info = get_callback_id_names();
auto code_obj_data = common::Synchronized<code_object_data_map_t, true>{};
auto kernel_data = common::Synchronized<kernel_symbol_data_map_t, true>{};
auto counter_dimension_data = common::Synchronized<counter_dimension_info_map_t, true>{};
auto target_kernels = common::Synchronized<targeted_kernels_set_t>{};
auto dispatch_index = std::atomic<uint64_t>{0};
auto* buffered_name_info = as_pointer(get_buffer_id_names());
auto* callback_name_info = as_pointer(get_callback_id_names());
bool
add_kernel_target(uint64_t _kern_id)
{
return target_kernels
.wlock([](targeted_kernels_set_t& _targets_v,
uint64_t _kern_id_v) { return _targets_v.emplace(_kern_id_v); },
_kern_id)
.second;
}
bool
is_targeted_kernel(uint64_t _kern_id)
{
return target_kernels.rlock(
[](const targeted_kernels_set_t& _targets_v, uint64_t _kern_id_v) {
return (_targets_v.count(_kern_id_v) > 0);
},
_kern_id);
}
auto&
get_client_ctx()
@@ -328,15 +385,16 @@ cntrl_tracing_callback(rocprofiler_callback_tracing_record_t record,
auto ts = rocprofiler_timestamp_t{};
rocprofiler_get_timestamp(&ts);
const auto* kind_name = callback_name_info.kind_names.at(record.kind);
const auto* kind_name = CHECK_NOTNULL(callback_name_info)->kind_names.at(record.kind);
if(record.phase == ROCPROFILER_CALLBACK_PHASE_ENTER)
{
user_data->value = ts;
}
else
{
const auto* op_name =
callback_name_info.operation_names.at(record.kind).at(record.operation);
const auto* op_name = CHECK_NOTNULL(callback_name_info)
->operation_names.at(record.kind)
.at(record.operation);
auto ss = std::stringstream{};
tool::csv::marker_csv_encoder::write_row(ss,
kind_name,
@@ -368,7 +426,7 @@ callback_tracing_callback(rocprofiler_callback_tracing_record_t record,
auto ts = rocprofiler_timestamp_t{};
rocprofiler_get_timestamp(&ts);
const auto* kind_name = callback_name_info.kind_names.at(record.kind);
const auto* kind_name = CHECK_NOTNULL(callback_name_info)->kind_names.at(record.kind);
if(record.operation == ROCPROFILER_MARKER_CORE_API_ID_roctxMarkA)
{
if(record.phase == ROCPROFILER_CALLBACK_PHASE_EXIT)
@@ -460,8 +518,9 @@ callback_tracing_callback(rocprofiler_callback_tracing_record_t record,
}
else
{
const auto* op_name =
callback_name_info.operation_names.at(record.kind).at(record.operation);
const auto* op_name = CHECK_NOTNULL(callback_name_info)
->operation_names.at(record.kind)
.at(record.operation);
auto ss = std::stringstream{};
tool::csv::marker_csv_encoder::write_row(ss,
kind_name,
@@ -481,78 +540,6 @@ callback_tracing_callback(rocprofiler_callback_tracing_record_t record,
(void) data;
}
void
counter_record_callback(rocprofiler_queue_id_t,
const rocprofiler_agent_id_t,
rocprofiler_correlation_id_t correlation_id,
uint64_t,
void*,
size_t record_count,
rocprofiler_record_counter_t* record_data)
{
rocprofiler_tool_kernel_properties_t kernel_properties =
GetKernelProperties(correlation_id.internal);
std::map<const char*, uint64_t> counter_name_value;
for(size_t count = 0; count < record_count; count++)
{
auto profiler_record = static_cast<rocprofiler_record_counter_t>(record_data[count]);
rocprofiler_counter_id_t counter_id;
rocprofiler_query_record_counter_id(profiler_record.id, &counter_id);
rocprofiler_counter_info_v0_t version;
ROCPROFILER_CALL(
rocprofiler_query_counter_info(
counter_id, ROCPROFILER_COUNTER_INFO_VERSION_0, static_cast<void*>(&version)),
"Could not query counter_id");
const auto& dimension_pos_ss = counter_dimension_data.rlock(
[&profiler_record](const counter_dimension_info_map_t& counter_dimension_data_v,
uint64_t handle) {
auto dimensions = counter_dimension_data_v.at(handle);
size_t pos;
auto pos_ss = std::stringstream{};
size_t num_dim = dimensions.size();
for(size_t idx = 0; idx != num_dim; idx++)
{
rocprofiler_query_record_dimension_position(
profiler_record.id, dimensions[idx].id, &pos);
pos_ss << dimensions[idx].name << ":" << pos;
if(idx != num_dim - 1) pos_ss << ",";
}
return pos_ss;
},
counter_id.handle);
auto search = counter_name_value.find(version.name);
if(search == counter_name_value.end())
counter_name_value.emplace(
std::pair<const char*, uint64_t>{version.name, profiler_record.counter_value});
else
search->second = search->second + profiler_record.counter_value;
}
for(auto itr = counter_name_value.begin(); itr != counter_name_value.end(); ++itr)
{
auto counter_collection_ss = std::stringstream{};
tool::csv::counter_collection_csv_encoder::write_row(
counter_collection_ss,
correlation_id.internal,
kernel_properties.dispatch_index,
kernel_properties.gpu_agent.id.handle,
kernel_properties.queue_id.handle,
getpid(),
kernel_properties.thread_id,
kernel_properties.grid_size,
kernel_properties.kernel_name,
kernel_properties.workgroup_size,
((kernel_properties.lds_size + (lds_block_size - 1)) & ~(lds_block_size - 1)),
kernel_properties.scratch_size,
kernel_properties.arch_vgpr_count,
kernel_properties.sgpr_count,
itr->first,
itr->second);
get_dereference(get_counter_collection_file()) << counter_collection_ss.str();
}
}
void
code_object_tracing_callback(rocprofiler_callback_tracing_record_t record,
rocprofiler_user_data_t* user_data,
@@ -561,7 +548,19 @@ code_object_tracing_callback(rocprofiler_callback_tracing_record_t record,
if(record.kind == ROCPROFILER_CALLBACK_TRACING_CODE_OBJECT &&
record.operation == ROCPROFILER_CALLBACK_TRACING_CODE_OBJECT_LOAD)
{
if(record.phase == ROCPROFILER_CALLBACK_PHASE_UNLOAD)
if(record.phase == ROCPROFILER_CALLBACK_PHASE_LOAD)
{
auto* obj_data = static_cast<rocprofiler_code_object_data_t*>(record.payload);
if(record.phase == ROCPROFILER_CALLBACK_PHASE_LOAD)
{
code_obj_data.wlock(
[](code_object_data_map_t& cdata, rocprofiler_code_object_data_t* obj_data_v) {
cdata.emplace(obj_data_v->code_object_id, *obj_data_v);
},
CHECK_NOTNULL(obj_data));
}
}
else if(record.phase == ROCPROFILER_CALLBACK_PHASE_UNLOAD)
{
flush();
}
@@ -573,11 +572,50 @@ code_object_tracing_callback(rocprofiler_callback_tracing_record_t record,
auto* sym_data = static_cast<rocprofiler_kernel_symbol_data_t*>(record.payload);
if(record.phase == ROCPROFILER_CALLBACK_PHASE_LOAD)
{
kernel_data.wlock(
auto itr = kernel_data.wlock(
[](kernel_symbol_data_map_t& kdata, rocprofiler_kernel_symbol_data_t* sym_data_v) {
kdata.emplace(sym_data_v->kernel_id, kernel_symbol_data{*sym_data_v});
return kdata.emplace(sym_data_v->kernel_id, kernel_symbol_data{*sym_data_v});
},
sym_data);
CHECK_NOTNULL(sym_data));
LOG_IF(WARNING, !itr.second)
<< "duplicate kernel symbol data for kernel_id=" << sym_data->kernel_id;
// add the kernel to the kernel_targets if
if(itr.second)
{
// if kernel name is provided by user then by default all kernels in the application
// are targeted
if(tool::get_config().kernel_names.empty())
{
add_kernel_target(sym_data->kernel_id);
}
else
{
const auto& kernel_info = itr.first->second;
for(const auto& name : tool::get_config().kernel_names)
{
if(name == kernel_info.truncated_kernel_name)
{
add_kernel_target(itr.first->first);
break;
}
else
{
auto dkernel_name = std::string_view{kernel_info.demangled_kernel_name};
auto pos = dkernel_name.find(name);
// if the demangled kernel name contains name and the next character is
// '(' then mark as found
if(pos != std::string::npos && (pos + 1) < dkernel_name.size() &&
dkernel_name.at(pos + 1) == '(')
{
add_kernel_target(itr.first->first);
break;
}
}
}
}
}
}
}
@@ -622,7 +660,7 @@ buffered_tracing_callback(rocprofiler_context_id_t /*context*/,
auto kernel_trace_ss = std::stringstream{};
tool::csv::kernel_trace_csv_encoder::write_row(
kernel_trace_ss,
buffered_name_info.kind_names.at(record->kind),
CHECK_NOTNULL(buffered_name_info)->kind_names.at(record->kind),
record->agent_id.handle,
record->queue_id.handle,
record->kernel_id,
@@ -652,8 +690,10 @@ buffered_tracing_callback(rocprofiler_context_id_t /*context*/,
auto hsa_trace_ss = std::stringstream{};
tool::csv::api_csv_encoder::write_row(
hsa_trace_ss,
buffered_name_info.kind_names.at(record->kind),
buffered_name_info.operation_names.at(record->kind).at(record->operation),
CHECK_NOTNULL(buffered_name_info)->kind_names.at(record->kind),
CHECK_NOTNULL(buffered_name_info)
->operation_names.at(record->kind)
.at(record->operation),
getpid(),
record->thread_id,
record->correlation_id.internal,
@@ -670,8 +710,10 @@ buffered_tracing_callback(rocprofiler_context_id_t /*context*/,
auto memory_copy_trace_ss = std::stringstream{};
tool::csv::memory_copy_csv_encoder::write_row(
memory_copy_trace_ss,
buffered_name_info.kind_names.at(record->kind),
buffered_name_info.operation_names.at(record->kind).at(record->operation),
CHECK_NOTNULL(buffered_name_info)->kind_names.at(record->kind),
CHECK_NOTNULL(buffered_name_info)
->operation_names.at(record->kind)
.at(record->operation),
record->src_agent_id.handle,
record->dst_agent_id.handle,
record->correlation_id.internal,
@@ -689,8 +731,10 @@ buffered_tracing_callback(rocprofiler_context_id_t /*context*/,
auto hip_trace_ss = std::stringstream{};
tool::csv::api_csv_encoder::write_row(
hip_trace_ss,
buffered_name_info.kind_names.at(record->kind),
buffered_name_info.operation_names.at(record->kind).at(record->operation),
CHECK_NOTNULL(buffered_name_info)->kind_names.at(record->kind),
CHECK_NOTNULL(buffered_name_info)
->operation_names.at(record->kind)
.at(record->operation),
getpid(),
record->thread_id,
record->correlation_id.internal,
@@ -710,7 +754,7 @@ buffered_tracing_callback(rocprofiler_context_id_t /*context*/,
using counter_vec_t = std::vector<rocprofiler_counter_id_t>;
using agent_counter_map_t =
std::unordered_map<const rocprofiler_agent_t*, std::optional<rocprofiler_profile_config_id_t>>;
std::unordered_map<rocprofiler_agent_id_t, std::optional<rocprofiler_profile_config_id_t>>;
rocprofiler_status_t
dimensions_info_callback(rocprofiler_counter_id_t id,
@@ -740,14 +784,14 @@ dimensions_info_callback(rocprofiler_counter_id_t id,
// this function creates a rocprofiler profile config on the first entry
auto
get_agent_profile(const rocprofiler_agent_t* agent)
get_agent_profile(rocprofiler_agent_id_t agent_id)
{
static auto data = common::Synchronized<agent_counter_map_t>{};
auto profile = std::optional<rocprofiler_profile_config_id_t>{};
data.ulock(
[agent, &profile](const agent_counter_map_t& data_v) {
auto itr = data_v.find(agent);
[agent_id, &profile](const agent_counter_map_t& data_v) {
auto itr = data_v.find(agent_id);
if(itr != data_v.end())
{
profile = itr->second;
@@ -755,11 +799,11 @@ get_agent_profile(const rocprofiler_agent_t* agent)
}
return false;
},
[agent, &profile](agent_counter_map_t& data_v) {
[agent_id, &profile](agent_counter_map_t& data_v) {
auto counters_v = counter_vec_t{};
ROCPROFILER_CALL(
rocprofiler_iterate_agent_supported_counters(
agent->id,
agent_id,
[](rocprofiler_agent_id_t,
rocprofiler_counter_id_t* counters,
size_t num_counters,
@@ -771,15 +815,15 @@ get_agent_profile(const rocprofiler_agent_t* agent)
counters[i], dimensions_info_callback, nullptr),
"iterate_dimension_info");
rocprofiler_counter_info_v0_t version;
rocprofiler_counter_info_v0_t info;
ROCPROFILER_CALL(
rocprofiler_query_counter_info(counters[i],
ROCPROFILER_COUNTER_INFO_VERSION_0,
static_cast<void*>(&version)),
static_cast<void*>(&info)),
"Could not query counter_id");
if(tool::get_config().counters.count(version.name) > 0)
if(tool::get_config().counters.count(info.name) > 0)
vec->emplace_back(counters[i]);
}
return ROCPROFILER_STATUS_SUCCESS;
@@ -791,18 +835,122 @@ get_agent_profile(const rocprofiler_agent_t* agent)
{
auto profile_v = rocprofiler_profile_config_id_t{};
ROCPROFILER_CALL(rocprofiler_create_profile_config(
agent->id, counters_v.data(), counters_v.size(), &profile_v),
agent_id, counters_v.data(), counters_v.size(), &profile_v),
"Could not construct profile cfg");
profile = profile_v;
}
data_v.emplace(agent, profile);
data_v.emplace(agent_id, profile);
return true;
});
return profile;
}
struct counter_dispatch_data
{
uint64_t thread_id = 0;
uint64_t dispatch_index = 0;
};
void
dispatch_callback(rocprofiler_profile_counting_dispatch_data_t dispatch_data,
rocprofiler_profile_config_id_t* config,
rocprofiler_user_data_t* user_data,
void* /*callback_data_args*/)
{
auto kernel_id = dispatch_data.kernel_id;
auto agent_id = dispatch_data.agent_id;
if(!is_targeted_kernel(kernel_id))
{
return;
}
else if(auto profile = get_agent_profile(agent_id))
{
*config = *profile;
user_data->ptr = new counter_dispatch_data{.thread_id = common::get_tid(),
.dispatch_index = ++dispatch_index};
}
}
void
counter_record_callback(rocprofiler_profile_counting_dispatch_data_t dispatch_data,
rocprofiler_record_counter_t* record_data,
size_t record_count,
rocprofiler_user_data_t user_data,
void* /*callback_data_args*/)
{
auto kernel_id = dispatch_data.kernel_id;
const auto* cnt_dispatch_data_v = static_cast<counter_dispatch_data*>(user_data.ptr);
const auto* kernel_info = kernel_data.rlock(
[](const kernel_symbol_data_map_t& kdata, uint64_t kid) -> const auto* {
return &kdata.at(kid);
},
kernel_id);
LOG_IF(FATAL, !kernel_info) << "missing kernel information for kernel_id=" << kernel_id;
LOG_IF(ERROR, record_count == 0) << "zero record count for kernel_id=" << kernel_id
<< " (name=" << kernel_info->kernel_name << ")";
auto counter_name_value = std::map<const char*, uint64_t>{};
for(size_t count = 0; count < record_count; count++)
{
auto profiler_record = static_cast<rocprofiler_record_counter_t>(record_data[count]);
auto counter_id = rocprofiler_counter_id_t{};
auto info = rocprofiler_counter_info_v0_t{};
ROCPROFILER_CALL(rocprofiler_query_record_counter_id(profiler_record.id, &counter_id),
"query record counter id");
ROCPROFILER_CALL(
rocprofiler_query_counter_info(
counter_id, ROCPROFILER_COUNTER_INFO_VERSION_0, static_cast<void*>(&info)),
"query counter info");
auto search = counter_name_value.find(info.name);
if(search == counter_name_value.end())
counter_name_value.emplace(
std::pair<const char*, uint64_t>{info.name, profiler_record.counter_value});
else
search->second = search->second + profiler_record.counter_value;
}
auto lds_block_size_v =
(kernel_info->group_segment_size + (lds_block_size - 1)) & ~(lds_block_size - 1);
const auto& correlation_id = dispatch_data.correlation_id;
auto magnitude = [](rocprofiler_dim3_t dims) { return (dims.x * dims.y * dims.z); };
for(auto& itr : counter_name_value)
{
using csv_encoder = tool::csv::counter_collection_csv_encoder;
auto counter_collection_ss = std::stringstream{};
csv_encoder::write_row(counter_collection_ss,
correlation_id.internal,
cnt_dispatch_data_v->dispatch_index,
dispatch_data.agent_id.handle,
dispatch_data.queue_id.handle,
getpid(),
cnt_dispatch_data_v->thread_id,
magnitude(dispatch_data.grid_size),
kernel_info->formatted_kernel_name,
magnitude(dispatch_data.workgroup_size),
lds_block_size_v,
kernel_info->private_segment_size,
kernel_info->arch_vgpr_count,
kernel_info->sgpr_count,
itr.first,
itr.second);
get_dereference(get_counter_collection_file()) << counter_collection_ss.str();
}
delete cnt_dispatch_data_v;
}
rocprofiler_status_t
list_metrics_iterate_agents(rocprofiler_agent_version_t,
const void** agents,
@@ -912,61 +1060,6 @@ list_metrics_iterate_agents(rocprofiler_agent_version_t,
return ROCPROFILER_STATUS_SUCCESS;
}
void
dispatch_callback(rocprofiler_queue_id_t queue_id,
const rocprofiler_agent_t* agent,
rocprofiler_correlation_id_t correlation_id,
const hsa_kernel_dispatch_packet_t* dispatch_packet,
uint64_t kernel_id,
void* /*callback_data_args*/,
rocprofiler_profile_config_id_t* config)
{
rocprofiler_tool_kernel_properties_t kernel_properties;
const auto& kernel_info =
kernel_data.rlock([](const kernel_symbol_data_map_t& kdata,
uint64_t kernel_id_v) { return kdata.at(kernel_id_v); },
kernel_id);
auto is_targeted_kernel = [&kernel_info]() {
// if kernel name is provided by user then by default all kernels in the application are
// targeted
if(tool::get_config().kernel_names.empty()) return true;
for(const auto& name : tool::get_config().kernel_names)
{
if(name == kernel_info.truncated_kernel_name)
return true;
else
{
auto dkernel_name = std::string_view{kernel_info.demangled_kernel_name};
auto pos = dkernel_name.find(name);
// if the demangled kernel name contains name and the next character is '(' then
// mark as found
if(pos != std::string::npos && (pos + 1) < dkernel_name.size() &&
dkernel_name.at(pos + 1) == '(')
return true;
}
}
return false;
};
if(!is_targeted_kernel()) return;
auto profile = get_agent_profile(agent);
if(profile)
{
kernel_properties.kernel_name = kernel_info.formatted_kernel_name;
kernel_properties.dispatch_index = ++dispatch_index;
kernel_properties.queue_id = queue_id;
kernel_properties.gpu_agent = *agent;
kernel_properties.thread_id = common::get_tid();
populate_kernel_properties_data(&kernel_properties, dispatch_packet);
SetKernelProperties(correlation_id.internal, kernel_properties);
*config = *profile;
}
}
rocprofiler_client_finalize_t client_finalizer = nullptr;
rocprofiler_client_id_t* client_identifier = nullptr;
@@ -1059,7 +1152,8 @@ tool_init(rocprofiler_client_finalize_t fini_func, void* tool_data)
"buffer tracing service for memory copy configure");
}
if(tool::get_config().hsa_api_trace)
if(tool::get_config().hsa_core_api_trace || tool::get_config().hsa_amd_ext_api_trace ||
tool::get_config().hsa_image_ext_api_trace || tool::get_config().hsa_finalizer_ext_api_trace)
{
ROCPROFILER_CALL(rocprofiler_create_buffer(get_client_ctx(),
buffer_size,
@@ -1070,18 +1164,27 @@ tool_init(rocprofiler_client_finalize_t fini_func, void* tool_data)
&get_buffers().hsa_api_trace),
"buffer creation");
for(auto itr : {ROCPROFILER_BUFFER_TRACING_HSA_CORE_API,
ROCPROFILER_BUFFER_TRACING_HSA_AMD_EXT_API,
ROCPROFILER_BUFFER_TRACING_HSA_IMAGE_EXT_API,
ROCPROFILER_BUFFER_TRACING_HSA_FINALIZE_EXT_API})
using optpair_t = std::pair<bool, rocprofiler_buffer_tracing_kind_t>;
for(auto itr : {optpair_t{tool::get_config().hsa_core_api_trace,
ROCPROFILER_BUFFER_TRACING_HSA_CORE_API},
optpair_t{tool::get_config().hsa_core_api_trace,
ROCPROFILER_BUFFER_TRACING_HSA_AMD_EXT_API},
optpair_t{tool::get_config().hsa_core_api_trace,
ROCPROFILER_BUFFER_TRACING_HSA_IMAGE_EXT_API},
optpair_t{tool::get_config().hsa_core_api_trace,
ROCPROFILER_BUFFER_TRACING_HSA_FINALIZE_EXT_API}})
{
ROCPROFILER_CALL(rocprofiler_configure_buffer_tracing_service(
get_client_ctx(), itr, nullptr, 0, get_buffers().hsa_api_trace),
"buffer tracing service for hsa api configure");
if(itr.first)
{
ROCPROFILER_CALL(
rocprofiler_configure_buffer_tracing_service(
get_client_ctx(), itr.second, nullptr, 0, get_buffers().hsa_api_trace),
"buffer tracing service for hsa api configure");
}
}
}
if(tool::get_config().hip_api_trace || tool::get_config().hip_compiler_api_trace)
if(tool::get_config().hip_runtime_api_trace || tool::get_config().hip_compiler_api_trace)
{
ROCPROFILER_CALL(rocprofiler_create_buffer(get_client_ctx(),
buffer_size,
@@ -1092,7 +1195,7 @@ tool_init(rocprofiler_client_finalize_t fini_func, void* tool_data)
&get_buffers().hip_api_trace),
"buffer creation");
if(tool::get_config().hip_api_trace)
if(tool::get_config().hip_runtime_api_trace)
{
ROCPROFILER_CALL(rocprofiler_configure_buffer_tracing_service(
get_client_ctx(),
@@ -1187,7 +1290,8 @@ rocprofiler_configure(uint32_t version,
uint32_t priority,
rocprofiler_client_id_t* id)
{
common::init_logging("ROCPROF_LOG_LEVEL");
auto logging_cfg = rocprofiler::common::logging_config{.install_failure_handler = true};
common::init_logging("ROCPROF_LOG_LEVEL", logging_cfg);
FLAGS_colorlogtostderr = true;
// set the client name
@@ -1205,6 +1309,10 @@ rocprofiler_configure(uint32_t version,
uint32_t minor = (version % 10000) / 100;
uint32_t patch = version % 100;
// ensure these pointers are not leaked
add_destructor(buffered_name_info);
add_destructor(callback_name_info);
if(tool::get_config().list_metrics)
{
ROCPROFILER_CALL(rocprofiler_at_intercept_table_registration(