Files
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

318 lines
9.5 KiB
C++

// MIT License
//
// Copyright (c) 2026 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.
#include "att_no_intercept_impl.hpp"
#include "lib/common/logging.hpp"
#include <rocprofiler-sdk/context.h>
#include <rocprofiler-sdk/rocprofiler.h>
#include <fmt/core.h>
#include <limits>
#include <memory>
#include <string_view>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#define CHECK_PTR(_x) ROCP_FATAL_IF(_x == nullptr) << "Called after finalize()";
namespace rocprofiler
{
namespace tool
{
namespace att_no_intercept
{
namespace
{
using agent_state_map_t = std::unordered_map<uint64_t, std::shared_ptr<agent_state_t>>;
std::mutex manager_mutex{};
// Never used after global destructor
std::unordered_map<uint64_t, std::shared_ptr<agent_state_t>> code_objects{};
agent_state_map_t*&
agent_states()
{
static auto* _v = new agent_state_map_t{};
CHECK_PTR(_v);
return _v;
}
shader_data_forwarder_t&
shader_data_forwarder()
{
static auto _v = shader_data_forwarder_t{};
return _v;
}
std::unordered_set<size_t>&
kernel_filter_range()
{
static auto _v = std::unordered_set<size_t>{};
return _v;
}
void
check_status(rocprofiler_status_t status, std::string_view msg)
{
ROCP_FATAL_IF(status != ROCPROFILER_STATUS_SUCCESS)
<< msg << " failed with error code " << status << ": "
<< rocprofiler_get_status_string(status);
}
void
add_range_locked(agent_state_t& state,
uint64_t code_object_id,
uint64_t begin,
uint64_t size,
bool targeted)
{
if(begin == 0) return;
auto end = uint64_t{0};
if(size > 0 && begin <= std::numeric_limits<uint64_t>::max() - size)
end = begin + size;
else if(size > 0)
end = std::numeric_limits<uint64_t>::max();
else
end = begin + 1;
state.kernel_ranges_by_code_object[code_object_id].emplace_back(
kernel_symbol_range_t{begin, end, targeted});
}
void
add_exact_locked(agent_state_t& state, uint64_t code_object_id, uint64_t address, bool targeted)
{
if(address == 0) return;
state.kernel_iterations_by_entry[entry_key_t{code_object_id, address}] =
targeted ? std::make_shared<std::atomic<size_t>>(0) : nullptr;
}
uint64_t
get_symbol_size_locked(const code_object_record_t& code_object, uint64_t kernel_address)
{
auto elf_vaddr = kernel_address - static_cast<uint64_t>(code_object.load_delta);
if(auto itr = code_object.symbol_sizes_by_vaddr.find(elf_vaddr);
itr != code_object.symbol_sizes_by_vaddr.end())
return itr->second;
return 0;
}
void
register_kernel_symbol_locked(agent_state_t& state, const kernel_symbol_t& symbol, bool targeted)
{
auto code_object_itr = state.code_objects.find(symbol.code_object_id);
auto symbol_size = uint64_t{0};
if(code_object_itr != state.code_objects.end())
symbol_size = get_symbol_size_locked(code_object_itr->second, symbol.kernel_address.handle);
add_exact_locked(state, 0, symbol.kernel_address.handle, targeted);
add_range_locked(state, 0, symbol.kernel_address.handle, symbol_size, targeted);
if(code_object_itr == state.code_objects.end()) return;
const auto& code_object = code_object_itr->second;
auto elf_vaddr = symbol.kernel_address.handle - static_cast<uint64_t>(code_object.load_delta);
add_exact_locked(state, symbol.code_object_id, elf_vaddr, targeted);
add_range_locked(state, symbol.code_object_id, elf_vaddr, symbol_size, targeted);
}
void
start_agent_context(agent_state_t& state)
{
auto lock = std::unique_lock{state.mutex};
if(state.started || state.finalized) return;
state.started = true;
ROCP_INFO << fmt::format("starting ATT no-intercept context for agent {}", state.id.handle);
check_status(rocprofiler_start_context(state.context), "ATT no-intercept context start");
}
void
stop_agent_context(agent_state_t& state)
{
auto stop_context = false;
{
auto lock = std::unique_lock{state.mutex};
stop_context = state.started;
state.started = false;
state.finalized = true;
}
if(!stop_context) return;
auto status = rocprofiler_stop_context(state.context);
if(status != ROCPROFILER_STATUS_SUCCESS && status != ROCPROFILER_STATUS_ERROR_CONTEXT_NOT_FOUND)
{
check_status(status, "ATT no-intercept context stop");
}
}
} // namespace
bool
is_supported()
{
return backend_supported();
}
void
configure(shader_data_forwarder_t forwarder, std::unordered_set<size_t> filter_range)
{
ROCP_FATAL_IF(!backend_supported())
<< "--att-no-intercept was requested, but this rocprofv3 build was configured with "
"ROCPROFILER_DISABLE_ATT_QUICK_SCAN=ON and does not include "
"rocprof-trace-decoder quick-scan support";
ROCP_FATAL_IF(forwarder == nullptr)
<< "ATT no-intercept setup requires a shader-data forwarding callback";
auto lock = std::unique_lock{manager_mutex};
shader_data_forwarder() = forwarder;
kernel_filter_range() = std::move(filter_range);
}
agent_trace_config_t
configure_agent(rocprofiler_agent_id_t id, uint64_t consecutive_kernels)
{
auto lock = std::unique_lock{manager_mutex};
if(auto itr = agent_states()->find(id.handle); itr != agent_states()->end())
return agent_trace_config_t{itr->second->context, itr->second->userdata};
auto state = std::make_shared<agent_state_t>();
state->id = id;
state->consecutive_kernels = consecutive_kernels;
state->userdata.ptr = state.get();
check_status(rocprofiler_create_context(&state->context), "ATT no-intercept context creation");
backend_create(*state);
auto trace_config = agent_trace_config_t{state->context, state->userdata};
agent_states()->emplace(id.handle, std::move(state));
ROCP_INFO << fmt::format("configured ATT no-intercept context for agent {}", id.handle);
return trace_config;
}
void
shader_data_callback(rocprofiler_thread_trace_shader_data_t shader_data,
rocprofiler_user_data_t userdata)
{
auto* state = static_cast<agent_state_t*>(userdata.ptr);
if(state == nullptr || shader_data_forwarder() == nullptr) return;
backend_shader_data(*state, shader_data, shader_data_forwarder(), kernel_filter_range());
}
void
code_object_load(const rocprofiler_callback_tracing_code_object_load_data_t& data)
{
std::shared_ptr<agent_state_t> state = nullptr;
{
auto lock = std::unique_lock{manager_mutex};
auto itr = agent_states()->find(data.agent_id.handle);
if(itr == agent_states()->end()) return;
state = itr->second;
code_objects[data.code_object_id] = state;
}
{
auto lock = std::unique_lock{state->mutex};
state->code_objects[data.code_object_id] = code_object_record_t{data.load_delta};
}
backend_code_object_load(*state, data);
start_agent_context(*state);
}
void
kernel_symbol_load(const kernel_symbol_t& data, bool is_targeted)
{
std::shared_ptr<agent_state_t> state = nullptr;
{
auto lock = std::unique_lock{manager_mutex};
if(auto itr = code_objects.find(data.code_object_id); itr != code_objects.end())
{
state = itr->second;
}
else
{
ROCP_WARNING << "Unknown kernel symbol: " << data.kernel_id;
return;
}
}
auto lock = std::unique_lock{state->mutex};
register_kernel_symbol_locked(*state, data, is_targeted);
}
void
finalize()
{
auto lock = std::unique_lock{manager_mutex};
for(auto& itr : *agent_states())
{
auto& state = *itr.second;
stop_agent_context(state);
backend_destroy(state);
}
delete agent_states();
agent_states() = nullptr;
}
#if !defined(ROCPROFILER_ATT_QUICK_SCAN_ENABLED) || ROCPROFILER_ATT_QUICK_SCAN_ENABLED == 0
bool
backend_supported()
{
return false;
}
void
backend_create(agent_state_t&)
{}
void
backend_destroy(agent_state_t&)
{}
void
backend_code_object_load(agent_state_t&,
const rocprofiler_callback_tracing_code_object_load_data_t&)
{}
void
backend_shader_data(agent_state_t&,
rocprofiler_thread_trace_shader_data_t,
shader_data_forwarder_t,
const std::unordered_set<size_t>&)
{}
#endif
} // namespace att_no_intercept
} // namespace tool
} // namespace rocprofiler