SWDEV-396239: Automatic ISA dump from ATT
Change-Id: Ia66346c0048b779487157961ead08d7567c9153a
[ROCm/rocprofiler commit: a5555ac45f]
This commit is contained in:
committed by
Giovanni Baraldi
parent
6973eb4d8a
commit
f56282474c
@@ -50,6 +50,7 @@
|
||||
|
||||
#include "src/core/hsa/queues/queue.h"
|
||||
#include "src/api/rocprofiler_singleton.h"
|
||||
#include "src/core/isa_capture/code_object_track.hpp"
|
||||
|
||||
#include <experimental/filesystem>
|
||||
namespace fs = std::experimental::filesystem;
|
||||
@@ -464,6 +465,16 @@ hsa_status_t CodeObjectCallback(hsa_executable_t executable,
|
||||
data.codeobj.unload = *static_cast<bool*>(arg) ? 1 : 0;
|
||||
ReportActivity(ACTIVITY_DOMAIN_HSA_EVT, HSA_EVT_ID_CODEOBJ, &data);
|
||||
|
||||
if (data.codeobj.unload)
|
||||
codeobj_capture_instance::Unload(data.codeobj.load_base);
|
||||
else
|
||||
codeobj_capture_instance::Load(
|
||||
data.codeobj.load_base,
|
||||
uri_str,
|
||||
data.codeobj.memory_base,
|
||||
data.codeobj.memory_size
|
||||
);
|
||||
|
||||
hsa_executable_iterate_agent_symbols(executable, data.codeobj.agent,
|
||||
hsa_executable_iteration_callback, &(data.codeobj.unload));
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "src/core/hsa/packets/packets_generator.h"
|
||||
#include "src/core/hsa/hsa_support.h"
|
||||
#include "src/utils/helper.h"
|
||||
#include "src/core/isa_capture/code_object_track.hpp"
|
||||
|
||||
#define CHECK_HSA_STATUS(msg, status) \
|
||||
do { \
|
||||
@@ -493,17 +494,20 @@ bool AsyncSignalHandler(hsa_signal_value_t signal_value, void* data) {
|
||||
}
|
||||
|
||||
bool AsyncSignalHandlerATT(hsa_signal_value_t /* signal */, void* data) {
|
||||
// TODO: finish implementation to iterate trace data and add it to rocprofiler record
|
||||
// and generic buffer
|
||||
|
||||
auto queue_info_session = static_cast<queue_info_session_t*>(data);
|
||||
if (!queue_info_session || !GetROCProfilerSingleton() ||
|
||||
!GetROCProfilerSingleton()->GetSession(queue_info_session->session_id) ||
|
||||
!GetROCProfilerSingleton()->GetSession(queue_info_session->session_id)->GetAttTracer())
|
||||
if (!queue_info_session || !GetROCProfilerSingleton())
|
||||
return true;
|
||||
|
||||
rocprofiler::Session* session =
|
||||
GetROCProfilerSingleton()->GetSession(queue_info_session->session_id);
|
||||
if (!session) return true;
|
||||
|
||||
std::lock_guard<std::mutex> lock(session->GetSessionLock());
|
||||
|
||||
rocprofiler::att::AttTracer* att_tracer = session->GetAttTracer();
|
||||
if (!session->GetAttTracer()) return true;
|
||||
|
||||
std::vector<att_pending_signal_t>& pending_signals =
|
||||
const_cast<std::vector<att_pending_signal_t>&>(
|
||||
att_tracer->GetPendingSignals(queue_info_session->writer_id));
|
||||
@@ -512,9 +516,9 @@ bool AsyncSignalHandlerATT(hsa_signal_value_t /* signal */, void* data) {
|
||||
for (auto it = pending_signals.begin(); it != pending_signals.end();
|
||||
it = pending_signals.erase(it)) {
|
||||
auto& pending = *it;
|
||||
std::lock_guard<std::mutex> lock(session->GetSessionLock());
|
||||
if (hsa_support::GetCoreApiTable().hsa_signal_load_relaxed_fn(pending.new_signal))
|
||||
return true;
|
||||
|
||||
rocprofiler_record_att_tracer_t record{};
|
||||
record.kernel_id = rocprofiler_kernel_id_t{pending.kernel_descriptor};
|
||||
record.gpu_id = rocprofiler_agent_id_t{(uint64_t)queue_info_session->gpu_index};
|
||||
@@ -522,13 +526,18 @@ bool AsyncSignalHandlerATT(hsa_signal_value_t /* signal */, void* data) {
|
||||
record.thread_id = rocprofiler_thread_id_t{pending.thread_id};
|
||||
record.queue_idx = rocprofiler_queue_index_t{pending.queue_index};
|
||||
record.queue_id = rocprofiler_queue_id_t{queue_info_session->queue_id};
|
||||
record.writer_id = queue_info_session->writer_id;
|
||||
|
||||
if (/*pending.counters_count > 0 && */ pending.profile) {
|
||||
AddAttRecord(&record, queue_info_session->agent, pending);
|
||||
}
|
||||
// July/01/2023 -> Changed this to writer ID so we can correlate to dispatches
|
||||
// kernel_id already has the descriptor.
|
||||
// July/01/2023 -> Changed this to queue_info_session->writer_id
|
||||
// so we can correlate to dispatches. kernel_id already has the descriptor.
|
||||
record.header = {ROCPROFILER_ATT_TRACER_RECORD,
|
||||
rocprofiler_record_id_t{queue_info_session->writer_id}};
|
||||
rocprofiler_record_id_t{pending.kernel_descriptor}};
|
||||
|
||||
record.intercept_list = codeobj_record::get_capture(record.header.id);
|
||||
std::atomic_thread_fence(std::memory_order_release);
|
||||
|
||||
if (pending.session_id.handle == 0) {
|
||||
pending.session_id = GetROCProfilerSingleton()->GetCurrentSessionId();
|
||||
@@ -536,7 +545,10 @@ bool AsyncSignalHandlerATT(hsa_signal_value_t /* signal */, void* data) {
|
||||
if (session->FindBuffer(pending.buffer_id)) {
|
||||
Memory::GenericBuffer* buffer = session->GetBuffer(pending.buffer_id);
|
||||
buffer->AddRecord(record);
|
||||
buffer->Flush();
|
||||
}
|
||||
codeobj_record::free_capture(record.header.id);
|
||||
|
||||
hsa_status_t status = rocprofiler::hsa_support::GetAmdExtTable().hsa_amd_memory_pool_free_fn(
|
||||
(pending.profile->output_buffer.ptr));
|
||||
CHECK_HSA_STATUS("Error: Couldn't free output buffer memory", status);
|
||||
@@ -548,6 +560,7 @@ bool AsyncSignalHandlerATT(hsa_signal_value_t /* signal */, void* data) {
|
||||
}
|
||||
delete queue_info_session;
|
||||
|
||||
std::atomic_thread_fence(std::memory_order_seq_cst);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -721,17 +734,25 @@ std::pair<std::vector<bool>, bool> GetAllowedProfilesList(const void* packets, i
|
||||
return {can_profile_packet, b_can_profile_anypacket};
|
||||
}
|
||||
|
||||
hsa_ven_amd_aqlprofile_profile_t* ProcessATTParams(Packet::packet_t& start_packet,
|
||||
Packet::packet_t& stop_packet, Queue& queue_info,
|
||||
Agent::AgentInfo& agentInfo) {
|
||||
std::pair<hsa_ven_amd_aqlprofile_profile_t*, rocprofiler_codeobj_capture_mode_t>
|
||||
ProcessATTParams(
|
||||
Packet::packet_t& start_packet,
|
||||
Packet::packet_t& stop_packet,
|
||||
Queue& queue_info,
|
||||
Agent::AgentInfo& agentInfo
|
||||
) {
|
||||
std::vector<hsa_ven_amd_aqlprofile_parameter_t> att_params;
|
||||
int num_att_counters = 0;
|
||||
uint32_t att_buffer_size = DEFAULT_ATT_BUFFER_SIZE;
|
||||
rocprofiler_codeobj_capture_mode_t capture_mode = ROCPROFILER_CAPTURE_SYMBOLS_ONLY;
|
||||
|
||||
for (rocprofiler_att_parameter_t& param : att_parameters_data) {
|
||||
switch (param.parameter_name) {
|
||||
case ROCPROFILER_ATT_PERFCOUNTER_NAME:
|
||||
break;
|
||||
case ROCPROFILER_ATT_CAPTURE_MODE:
|
||||
capture_mode = static_cast<rocprofiler_codeobj_capture_mode_t>(param.value);
|
||||
break;
|
||||
case ROCPROFILER_ATT_BUFFER_SIZE:
|
||||
att_buffer_size =
|
||||
std::max(96l << 10l, std::min(int64_t(param.value) << 20l, (1l << 32l) - (3l << 20)));
|
||||
@@ -773,8 +794,8 @@ hsa_ven_amd_aqlprofile_profile_t* ProcessATTParams(Packet::packet_t& start_packe
|
||||
for (; num_att_counters < 16; num_att_counters++) att_params.push_back(zero_perf);
|
||||
}
|
||||
// Get the PM4 Packets using packets_generator
|
||||
return Packet::GenerateATTPackets(queue_info.GetCPUAgent(), queue_info.GetGPUAgent(), att_params,
|
||||
&start_packet, &stop_packet, att_buffer_size);
|
||||
return {Packet::GenerateATTPackets(queue_info.GetCPUAgent(), queue_info.GetGPUAgent(),
|
||||
att_params, &start_packet, &stop_packet, att_buffer_size), capture_mode};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -786,6 +807,7 @@ hsa_ven_amd_aqlprofile_profile_t* ProcessATTParams(Packet::packet_t& start_packe
|
||||
*/
|
||||
void WriteInterceptor(const void* packets, uint64_t pkt_count, uint64_t user_pkt_index, void* data,
|
||||
hsa_amd_queue_intercept_packet_writer writer) {
|
||||
|
||||
static const char* env_MAX_ATT_PROFILES = getenv("ROCPROFILER_MAX_ATT_PROFILES");
|
||||
static int MAX_ATT_PROFILES = env_MAX_ATT_PROFILES ? atoi(env_MAX_ATT_PROFILES) : 1;
|
||||
|
||||
@@ -952,9 +974,15 @@ void WriteInterceptor(const void* packets, uint64_t pkt_count, uint64_t user_pkt
|
||||
Packet::packet_t start_packet{};
|
||||
Packet::packet_t stop_packet{};
|
||||
hsa_ven_amd_aqlprofile_profile_t* profile = nullptr;
|
||||
rocprofiler_codeobj_capture_mode_t capture_mode = ROCPROFILER_CAPTURE_SYMBOLS_ONLY;
|
||||
|
||||
if (att_parameters_data.size() > 0 && is_att_collection_mode)
|
||||
profile = ProcessATTParams(start_packet, stop_packet, queue_info, agentInfo);
|
||||
if (att_parameters_data.size() > 0) {
|
||||
std::tie(profile, capture_mode) = ProcessATTParams(start_packet,
|
||||
stop_packet,
|
||||
queue_info,
|
||||
agentInfo
|
||||
);
|
||||
}
|
||||
|
||||
// Searching across all the packets given during this write
|
||||
for (size_t i = 0; i < pkt_count; ++i) {
|
||||
@@ -976,7 +1004,7 @@ void WriteInterceptor(const void* packets, uint64_t pkt_count, uint64_t user_pkt
|
||||
KernelInterceptCount += 1;
|
||||
writer_id = WRITER_ID.fetch_add(1, std::memory_order_release);
|
||||
|
||||
if (att_parameters_data.size() > 0 && is_att_collection_mode && profile) {
|
||||
if (att_parameters_data.size() > 0 && profile) {
|
||||
// Adding start packet and its barrier with a dummy signal
|
||||
hsa_signal_t dummy_signal{};
|
||||
dummy_signal.handle = 0;
|
||||
@@ -996,17 +1024,17 @@ void WriteInterceptor(const void* packets, uint64_t pkt_count, uint64_t user_pkt
|
||||
uint64_t record_id = GetROCProfilerSingleton()->GetUniqueRecordId();
|
||||
AddKernelNameWithDispatchID(GetKernelNameFromKsymbols(dispatch_packet.kernel_object),
|
||||
record_id);
|
||||
if (session && profile) {
|
||||
session->GetAttTracer()->AddPendingSignals(
|
||||
writer_id, record_id, original_packet.completion_signal,
|
||||
dispatch_packet.completion_signal, session_id_snapshot, buffer_id, profile,
|
||||
kernel_properties, (uint32_t)syscall(__NR_gettid), user_pkt_index);
|
||||
} else {
|
||||
session->GetAttTracer()->AddPendingSignals(
|
||||
writer_id, record_id, original_packet.completion_signal,
|
||||
dispatch_packet.completion_signal, session_id_snapshot, buffer_id, nullptr,
|
||||
kernel_properties, (uint32_t)syscall(__NR_gettid), user_pkt_index);
|
||||
}
|
||||
|
||||
session->GetAttTracer()->AddPendingSignals(
|
||||
writer_id, record_id, original_packet.completion_signal,
|
||||
dispatch_packet.completion_signal, session_id_snapshot, buffer_id, profile,
|
||||
kernel_properties, (uint32_t)syscall(__NR_gettid), user_pkt_index);
|
||||
|
||||
uint64_t off = dispatch_packet.kernel_object +
|
||||
GetKernelCode(dispatch_packet.kernel_object)->kernel_code_entry_byte_offset;
|
||||
codeobj_record::make_capture(rocprofiler_record_id_t{record_id}, capture_mode, off);
|
||||
codeobj_record::start_capture(rocprofiler_record_id_t{record_id});
|
||||
codeobj_record::stop_capture(rocprofiler_record_id_t{record_id});
|
||||
|
||||
// Make a copy of the original packet, adding its signal to a barrier packet
|
||||
if (original_packet.completion_signal.handle) {
|
||||
|
||||
@@ -0,0 +1,248 @@
|
||||
/* Copyright (c) 2023 Advanced Micro Devices, Inc.
|
||||
|
||||
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 <algorithm>
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
#include <cinttypes>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <sys/mman.h>
|
||||
#include <hsa/hsa.h>
|
||||
#include <amd-dbgapi/amd-dbgapi.h>
|
||||
#include <hsa/amd_hsa_kernel_code.h>
|
||||
#include <hsa/hsa_ven_amd_loader.h>
|
||||
#include <iostream>
|
||||
#include "src/utils/helper.h"
|
||||
#include "src/api/rocprofiler_singleton.h"
|
||||
#include "src/core/isa_capture/code_object_track.hpp"
|
||||
#include <amd_comgr/amd_comgr.h>
|
||||
|
||||
std::mutex codeobj_capture_instance::mutex;
|
||||
std::mutex codeobj_record::mutex;
|
||||
|
||||
std::unordered_map<uint64_t, CodeobjPtr> codeobj_capture_instance::codeobjs{};
|
||||
std::unordered_map<uint64_t, codeobj_record::RecordInstance> codeobj_record::record_id_map{};
|
||||
std::unordered_set<codeobj_record*> codeobj_record::listeners;
|
||||
|
||||
// Codeobj Record
|
||||
codeobj_record::codeobj_record(rocprofiler_codeobj_capture_mode_t mode) : capture_mode(mode){};
|
||||
|
||||
void codeobj_record::start_capture() {
|
||||
listeners.insert(this);
|
||||
for (auto& [addr, capture] : codeobj_capture_instance::codeobjs) this->addcapture(capture);
|
||||
}
|
||||
|
||||
void codeobj_record::addcapture(CodeobjPtr& capture) {
|
||||
if (captures.find(capture) != captures.end()) return;
|
||||
capture->setmode(capture_mode);
|
||||
captures.insert(capture);
|
||||
}
|
||||
|
||||
void codeobj_record::stop_capture() {
|
||||
try {
|
||||
listeners.erase(this);
|
||||
} catch (...) {
|
||||
};
|
||||
}
|
||||
|
||||
// Codeobj Capture
|
||||
void codeobj_capture_instance::Load(uint64_t addr, const std::string& URI, uint64_t mem_addr,
|
||||
uint64_t mem_size) {
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
codeobjs[addr] = std::make_shared<codeobj_capture_instance>(
|
||||
addr, URI, mem_addr, mem_size, rocprofiler::GetCurrentTimestamp().value);
|
||||
std::atomic_thread_fence(std::memory_order_release); // Fencing the state of the map
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(codeobj_record::mutex);
|
||||
for (auto* listen : codeobj_record::listeners) listen->addcapture(codeobjs.at(addr));
|
||||
}
|
||||
}
|
||||
|
||||
void codeobj_capture_instance::Unload(uint64_t addr) {
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
codeobjs.at(addr)->end_time = rocprofiler::GetCurrentTimestamp().value;
|
||||
codeobjs.erase(addr);
|
||||
}
|
||||
|
||||
void codeobj_capture_instance::copyCodeobjFromFile(uint64_t offset, uint64_t size,
|
||||
const std::string& decoded_path) {
|
||||
std::ifstream file(decoded_path, std::ios::in | std::ios::binary);
|
||||
if (!file) {
|
||||
printf("could not open `%s'\n", decoded_path.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!size) {
|
||||
file.ignore(std::numeric_limits<std::streamsize>::max());
|
||||
size_t bytes = file.gcount();
|
||||
file.clear();
|
||||
|
||||
if (bytes < offset) {
|
||||
printf("invalid uri `%s' (file size < offset)\n", decoded_path.c_str());
|
||||
return;
|
||||
}
|
||||
size = bytes - offset;
|
||||
}
|
||||
|
||||
file.seekg(offset, std::ios_base::beg);
|
||||
buffer.resize(size);
|
||||
file.read(&buffer[0], size);
|
||||
}
|
||||
|
||||
void codeobj_capture_instance::copyCodeobjFromMemory(uint64_t mem_addr, uint64_t mem_size) {
|
||||
buffer.resize(mem_size);
|
||||
std::memcpy(buffer.data(), (uint64_t*)mem_addr, mem_size);
|
||||
}
|
||||
|
||||
std::pair<size_t, size_t> codeobj_capture_instance::parse_uri() {
|
||||
const std::string protocol_delim{"://"};
|
||||
|
||||
size_t protocol_end = URI.find(protocol_delim);
|
||||
protocol = URI.substr(0, protocol_end);
|
||||
protocol_end += protocol_delim.length();
|
||||
|
||||
std::transform(protocol.begin(), protocol.end(), protocol.begin(),
|
||||
[](unsigned char c) { return std::tolower(c); });
|
||||
|
||||
std::string path;
|
||||
size_t path_end = URI.find_first_of("#?", protocol_end);
|
||||
if (path_end != std::string::npos) {
|
||||
path = URI.substr(protocol_end, path_end++ - protocol_end);
|
||||
} else {
|
||||
path = URI.substr(protocol_end);
|
||||
}
|
||||
|
||||
/* %-decode the string. */
|
||||
decoded_path = std::string{};
|
||||
decoded_path.reserve(path.length());
|
||||
for (size_t i = 0; i < path.length(); ++i) {
|
||||
if (path[i] == '%' && std::isxdigit(path[i + 1]) && std::isxdigit(path[i + 2])) {
|
||||
decoded_path += std::stoi(path.substr(i + 1, 2), 0, 16);
|
||||
i += 2;
|
||||
} else {
|
||||
decoded_path += path[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Tokenize the query/fragment. */
|
||||
std::vector<std::string> tokens;
|
||||
size_t pos, last = path_end;
|
||||
while ((pos = URI.find('&', last)) != std::string::npos) {
|
||||
tokens.emplace_back(URI.substr(last, pos - last));
|
||||
last = pos + 1;
|
||||
}
|
||||
if (last != std::string::npos) tokens.emplace_back(URI.substr(last));
|
||||
|
||||
/* Create a tag-value map from the tokenized query/fragment. */
|
||||
std::unordered_map<std::string, std::string> params;
|
||||
std::for_each(tokens.begin(), tokens.end(), [&](std::string& token) {
|
||||
size_t delim = token.find('=');
|
||||
if (delim != std::string::npos) {
|
||||
params.emplace(token.substr(0, delim), token.substr(delim + 1));
|
||||
}
|
||||
});
|
||||
|
||||
size_t offset{0}, size{0};
|
||||
|
||||
if (auto offset_it = params.find("offset"); offset_it != params.end())
|
||||
offset = std::stoul(offset_it->second, nullptr, 0);
|
||||
|
||||
if (auto size_it = params.find("size"); size_it != params.end()) {
|
||||
if (!(size = std::stoul(size_it->second, nullptr, 0))) throw std::exception();
|
||||
}
|
||||
|
||||
return {offset, size};
|
||||
}
|
||||
|
||||
codeobj_capture_instance::codeobj_capture_instance(uint64_t _addr, const std::string& _uri,
|
||||
uint64_t mem_addr, uint64_t mem_size,
|
||||
uint64_t start_time)
|
||||
: addr(_addr), start_time(start_time), URI(_uri), mem_addr(mem_addr), mem_size(mem_size) {
|
||||
reset(ROCPROFILER_CAPTURE_SYMBOLS_ONLY);
|
||||
};
|
||||
|
||||
void codeobj_capture_instance::setmode(rocprofiler_codeobj_capture_mode_t mode) {
|
||||
// Only reset when needed & check if codeobj was not unloaded
|
||||
if (end_time == 0 && static_cast<int>(mode) > static_cast<int>(capture_mode))
|
||||
reset(mode);
|
||||
}
|
||||
|
||||
void codeobj_capture_instance::reset(rocprofiler_codeobj_capture_mode_t mode) {
|
||||
capture_mode = mode;
|
||||
|
||||
size_t offset, size;
|
||||
try {
|
||||
std::tie(offset, size) = parse_uri();
|
||||
} catch (...) {
|
||||
return;
|
||||
}
|
||||
|
||||
buffer = std::vector<char>{};
|
||||
|
||||
if (mode == ROCPROFILER_CAPTURE_SYMBOLS_ONLY) return;
|
||||
|
||||
if (protocol == "file") {
|
||||
if (mode == ROCPROFILER_CAPTURE_COPY_FILE_AND_MEMORY)
|
||||
copyCodeobjFromFile(offset, size, decoded_path);
|
||||
} else if (protocol == "memory") {
|
||||
copyCodeobjFromMemory(mem_addr, mem_size);
|
||||
} else {
|
||||
printf("\"%s\" protocol not supported\n", protocol.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Public static funcs
|
||||
void codeobj_record::make_capture(rocprofiler_record_id_t id,
|
||||
rocprofiler_codeobj_capture_mode_t mode, uint64_t userdata) {
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
record_id_map[id.handle] = {userdata, std::unique_ptr<codeobj_record>{new codeobj_record(mode)}};
|
||||
}
|
||||
|
||||
void codeobj_record::free_capture(rocprofiler_record_id_t id) {
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
record_id_map.erase(id.handle);
|
||||
}
|
||||
|
||||
void codeobj_record::start_capture(rocprofiler_record_id_t id) {
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
record_id_map.at(id.handle).second->start_capture();
|
||||
}
|
||||
|
||||
void codeobj_record::stop_capture(rocprofiler_record_id_t id) {
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
record_id_map.at(id.handle).second->stop_capture();
|
||||
}
|
||||
|
||||
rocprofiler_codeobj_symbols_t codeobj_record::get_capture(rocprofiler_record_id_t id) {
|
||||
std::atomic_thread_fence(std::memory_order_acquire); // Fencing the state of the map
|
||||
auto& pair = record_id_map.at(id.handle);
|
||||
return pair.second->get(pair.first);
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
/* Copyright (c) 2023 Advanced Micro Devices, Inc.
|
||||
|
||||
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 "src/utils/helper.h"
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
|
||||
/**
|
||||
* A class to keep track of currently loaded code objects.
|
||||
* Only the public static methods are thread-safe and expected to be used.
|
||||
*/
|
||||
class codeobj_capture_instance {
|
||||
public:
|
||||
codeobj_capture_instance(uint64_t _addr, const std::string& _uri, uint64_t mem_addr,
|
||||
uint64_t mem_size, uint64_t start_time);
|
||||
|
||||
void setmode(rocprofiler_codeobj_capture_mode_t mode);
|
||||
|
||||
rocprofiler_intercepted_codeobj_t get() const {
|
||||
const char* buf_ptr = buffer.size() ? buffer.data() : nullptr;
|
||||
return {URI.c_str(), addr, buf_ptr, buffer.size(), start_time, end_time};
|
||||
};
|
||||
|
||||
const uint64_t addr;
|
||||
const uint64_t start_time;
|
||||
|
||||
static void Load(uint64_t addr, const std::string& URI, uint64_t mem_addr, uint64_t mem_size);
|
||||
static void Unload(uint64_t addr);
|
||||
|
||||
static std::unordered_map<uint64_t, std::shared_ptr<codeobj_capture_instance>> codeobjs;
|
||||
|
||||
private:
|
||||
void reset(rocprofiler_codeobj_capture_mode_t mode);
|
||||
|
||||
std::pair<size_t, size_t> parse_uri();
|
||||
void DecodePath();
|
||||
void copyCodeobjFromFile(uint64_t offset, uint64_t size, const std::string& decoded_path);
|
||||
void copyCodeobjFromMemory(uint64_t mem_addr, uint64_t mem_size);
|
||||
|
||||
std::string URI;
|
||||
std::string decoded_path;
|
||||
std::string protocol;
|
||||
std::vector<char> buffer;
|
||||
|
||||
uint64_t mem_addr;
|
||||
uint64_t mem_size;
|
||||
uint64_t end_time = 0;
|
||||
rocprofiler_codeobj_capture_mode_t capture_mode;
|
||||
|
||||
// Address -> codeobj
|
||||
static std::mutex mutex;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<codeobj_capture_instance> CodeobjPtr;
|
||||
|
||||
template <> struct std::hash<CodeobjPtr> {
|
||||
// addr is typically 2^12-byte aligned. Taking last 44 bits of time == cycle time of many hours.
|
||||
uint64_t operator()(const CodeobjPtr& p) const {
|
||||
return (p->addr >> 12) ^ (p->start_time << 20);
|
||||
};
|
||||
};
|
||||
|
||||
template <> struct std::equal_to<CodeobjPtr> {
|
||||
bool operator()(const CodeobjPtr& a, const CodeobjPtr& b) const {
|
||||
return (a->addr == b->addr) & (a->start_time == b->start_time);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* A class to keep track of the history of loaded code objets.
|
||||
* Only the public static methods are thread-safe and expected to be used.
|
||||
*/
|
||||
class codeobj_record {
|
||||
public:
|
||||
codeobj_record(rocprofiler_codeobj_capture_mode_t mode);
|
||||
~codeobj_record() {
|
||||
if (listeners.find(this) != listeners.end()) stop_capture();
|
||||
};
|
||||
|
||||
void addcapture(CodeobjPtr& capture);
|
||||
|
||||
public:
|
||||
static void make_capture(rocprofiler_record_id_t id, rocprofiler_codeobj_capture_mode_t mode,
|
||||
uint64_t userdata);
|
||||
static void free_capture(rocprofiler_record_id_t id);
|
||||
static void start_capture(rocprofiler_record_id_t id);
|
||||
static void stop_capture(rocprofiler_record_id_t id);
|
||||
static rocprofiler_codeobj_symbols_t get_capture(rocprofiler_record_id_t id);
|
||||
|
||||
static std::unordered_set<codeobj_record*> listeners;
|
||||
static std::mutex mutex;
|
||||
|
||||
private:
|
||||
rocprofiler_codeobj_symbols_t get(uint64_t userdata) {
|
||||
persist.clear();
|
||||
for (auto& capt : captures) persist.push_back(capt->get());
|
||||
return rocprofiler_codeobj_symbols_t{persist.data(), persist.size(), userdata};
|
||||
};
|
||||
|
||||
void start_capture();
|
||||
void stop_capture();
|
||||
|
||||
rocprofiler_codeobj_capture_mode_t capture_mode;
|
||||
std::vector<rocprofiler_intercepted_codeobj_t> persist;
|
||||
std::unordered_set<CodeobjPtr> captures;
|
||||
|
||||
// Record_id -> codeobj
|
||||
using RecordInstance = std::pair<uint64_t, std::unique_ptr<codeobj_record>>;
|
||||
static std::unordered_map<uint64_t, RecordInstance> record_id_map;
|
||||
};
|
||||
@@ -41,11 +41,9 @@ void AttTracer::AddPendingSignals(
|
||||
sessions_pending_signals_.at(writer_id).emplace_back(att_pending_signal_t{
|
||||
kernel_object, original_completion_signal, new_completion_signal, session_id_, buffer_id,
|
||||
profile, kernel_properties, thread_id, queue_index});
|
||||
std::atomic_thread_fence(std::memory_order_release);
|
||||
}
|
||||
|
||||
const std::vector<att_pending_signal_t>& AttTracer::GetPendingSignals(uint32_t writer_id) {
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
std::lock_guard<std::mutex> lock(sessions_pending_signals_lock_);
|
||||
assert(sessions_pending_signals_.find(writer_id) != sessions_pending_signals_.end() &&
|
||||
"writer_id is not found in the pending_signals");
|
||||
|
||||
Reference in New Issue
Block a user