Tools update (#397)

* Srnagara/tool counters collect (#331)

* Adding counter collection capability to tools

* Adding counter collection feature to tools

* Adding counter collection capability to tools

* Fixing merge down issues

* Small tool fixes for build + prevent profile realloc

* Reproducing the counter name query issue in buffered callback

* Minor fix for init order + sample that directly uses sdk-tool for debug purposes

* Adding a temporary fix to print the counter names

* Fixing the output file name and reverting the changes of caching the profile config

* Fixing SGPR_Count value

* cleaning up debug prints

* Adding header to counter collection file

* Adding kernel filtering support

* Remove threading

* Cleaning up the code

* Removing redundant prints

* Revert "Remove threading"

This reverts commit 05c58fb9de826e92cf8d2e3d1c31d5578525dcb4.

* Revert "Cleaning up the code"

This reverts commit 1d964882bf2396dee8ad020cbb6c83b36e0674e9.

* Changing the tools code to align with init-order fix

* cmake formatting (cmake-format) (#335)

Co-authored-by: SrirakshaNag <SrirakshaNag@users.noreply.github.com>

* source formatting (clang-format v11) (#336)

Co-authored-by: SrirakshaNag <SrirakshaNag@users.noreply.github.com>

* Adding support for async memory copy

* source formatting (clang-format v11) (#391)

Co-authored-by: SrirakshaNag <SrirakshaNag@users.noreply.github.com>

* Fixing header typo

* Fixing tool_fini

* Replaceing the direction and kind fields values with description

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

- Remove use of VLA

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

- Formatting

* Migrate common/config.* to rocprofiler-sdk-tool

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

- fix clang-tidy issues

* source formatting (clang-format v11) (#392)

Co-authored-by: jrmadsen <jrmadsen@users.noreply.github.com>

* Update lib/common/mpl.hpp

- is_string_type / is_string_type_impl for deducing if type is a string type

* Update include/rocprofiler-sdk/fwd.h

- ROCPROFILER_BUFFER_TRACING_MEMORY_COPY_NONE starts at zero

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

- functions for operation ids and names

* Update lib/rocprofiler-sdk/buffer_tracing.cpp

- support iterating and getting names for ROCPROFILER_BUFFER_TRACING_MEMORY_COPY

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

- env ROCPROFILER_ prefix -> ROCPROF_ prefix
- add support for memory copy tracing, counter collection, etc.

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

- removed TracerFlushRecord
- removed cxa_demangle (use one in common library)
- removed GetCounterNames (handled in config)
- removed GetKernelNames (handled in config)

* Add lib/rocprofiler-sdk-tool/output_file.*

- separate out get_output_stream function and output_file struct from tool.cpp

* Add lib/rocprofiler-sdk-tool/csv.hpp

- write_csv_entry automatically quotes strings
- csv_encoder struct enforces correct number of columns

* Update lib/rocprofiler-sdk-tool/CMakeLists.txt

- add new files

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

- update construction of output_file class
- add kernel_symbol_data for serializing kernel trace data
- use config instead of env lookups
- optimize counter collection profile config lookup/creation

* Update bin/rocprofv3

- rocprofv3 --help exits with 0 (as it should)
- command-line arg for memory copy tracing
- command-line arg for mangled kernels
- command-line arg for truncated kernels
- env ROCPROFILER_ prefix -> env ROCPROF_ prefix

* Update tests/async-copy-tracing/validate.py

- update test_async_copy_direction to new enum values

* Update tests/kernel-tracing/validate.py

- update test_async_copy_direction to new enum values

* Update tests/tools/json-tool.cpp

- add ROCPROFILER_BUFFER_TRACING_MEMORY_COPY to supported buffer_name_info

* Update samples/counter_collection/{CMakeLists.txt,main.cpp}

- remove counter-collection-sdk-tool

* Update .github/workflows/docs.yml

- fix paths triggering running the workflow

---------

Co-authored-by: Benjamin Welton <bewelton@amd.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: SrirakshaNag <SrirakshaNag@users.noreply.github.com>
Co-authored-by: Jonathan R. Madsen <jonathanrmadsen@gmail.com>
Co-authored-by: jrmadsen <jrmadsen@users.noreply.github.com>

* adding counter collection support

* Adding counter collection test

* changing directory structure of counter collection tests

* Fixing test path for rocprofv3

* Adding hsa-tracing basic test

* cmake formatting (cmake-format) (#362)

Co-authored-by: bgopesh <bgopesh@users.noreply.github.com>

* counter collection tests drop2

* fixing hsa-trace test for rocprofv3 path

* python formatting (black) (#371)

Co-authored-by: bgopesh <bgopesh@users.noreply.github.com>

* both counter colleciton and tracing should work together

* Fixing rocprofv3 path

* Attempt to fix Segfault with AddressSanitizer

* fixing sanitizer segfault

* Update rocprofv3

* Update lib/rocprofiler-sdk-tool/README.md

- update env variables

* Update lib/rocprofiler-sdk/buffer_tracing.cpp

- return ROCPROFILER_STATUS_BUFFER_NOT_FOUND if buffer tracing service is configured with invalid buffer

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

- designated hsa API trace buffer

* Update tests/hsa-tracing/CMakeLists.txt

- Fix environment

* Update rocprofv3

- do not override HSA_TOOLS_LIB
- support ROCPROF_PRELOAD
- LD_PRELOAD librocprofiler-sdk.so

* Restructure tests directory

- move all rocprofv3 integration tests into subfolder

* Update cmake/Templates/rocprofiler-sdk/config.cmake.in

- create rocprofiler-sdk::rocprofv3 cmake target

* Update tests/rocprofv3/hsa-tracing

- improve validate.py
- convert input to dict via csv.DictReader

* Update tests/apps/CMakeLists.txt

- fix build rpath for simple-transpose

* Update  cmake/rocprofiler_memcheck.cmake

- prefer libtsan.so.0

* Update tests/rocprofv3/hsa-tracing

- move to tests/rocprofv3/tracing
- include kernel tracing and memory copy tracing

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

- normalize "_ID" vs. "_Id" in CSV column names (use "_Id")

* Update lib/rocprofiler-sdk/buffer.{hpp,cpp}

- change signature of buffer::get_buffers()
- buffer::get_buffers() uses static_object

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

- update usage of buffer::get_buffers()
  - now returns pointer

* Update lib/rocprofiler-sdk/tests/buffer.cpp

- update to change for signature of buffer::get_buffers()

* Update tests/rocprofv3/tracing/CMakeLists.txt

- use %argt% with -d argument

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

- use atexit for finalization

* Update tests/rocprofv3/tracing/CMakeLists.txt

- tweaked name of tests

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

- async_copy_fini + reference counting signals

* Update lib/rocprofiler-sdk/registration.cpp

- invoke hsa::async_copy_fini() to prevent data race on signals

---------

Co-authored-by: SrirakshaNag <104580803+SrirakshaNag@users.noreply.github.com>
Co-authored-by: Benjamin Welton <bewelton@amd.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: SrirakshaNag <SrirakshaNag@users.noreply.github.com>
Co-authored-by: gobhardw <gopesh.bhardwaj@amd.com>
Co-authored-by: bgopesh <bgopesh@users.noreply.github.com>

[ROCm/rocprofiler-sdk commit: 1f4cf1aa39]
This commit is contained in:
Jonathan R. Madsen
2024-01-22 19:06:25 -06:00
committed by GitHub
parent 9e2726b408
commit 37d7930a60
51 changed files with 2031 additions and 648 deletions
@@ -20,192 +20,186 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include "config.hpp"
#include "csv.hpp"
#include "helper.hpp"
#include "rocprofiler-sdk/context.h"
#include "trace_buffer.hpp"
#include "output_file.hpp"
#include "lib/common/demangle.hpp"
#include "lib/common/environment.hpp"
#include "lib/common/filesystem.hpp"
#include "lib/common/logging.hpp"
#include "lib/common/synchronized.hpp"
#include "lib/common/utility.hpp"
#include <rocprofiler-sdk/agent.h>
#include <rocprofiler-sdk/fwd.h>
#include <rocprofiler-sdk/rocprofiler.h>
#include <glog/logging.h>
#include <fmt/core.h>
#include <unistd.h>
#include <cassert>
#include <fstream>
#include <iomanip>
#include <mutex>
#include <optional>
#include <shared_mutex>
#include <unordered_map>
#include <unordered_set>
#include <vector>
namespace common = ::rocprofiler::common;
namespace fs = common::filesystem;
TRACE_BUFFER_INSTANTIATE();
// static const uint32_t lds_block_size = 128 * 4;
namespace common = ::rocprofiler::common;
namespace tool = ::rocprofiler::tool;
static const uint32_t lds_block_size = 128 * 4;
namespace
{
auto tool_buffer = rocprofiler_buffer_id_t{};
auto context_id = rocprofiler_context_id_t{};
auto output_path =
fs::path{common::get_env<std::string>("ROCPROFILER_OUTPUT_PATH", fs::current_path().string())};
auto output_file_name =
common::get_env<std::string>("ROCPROFILER_OUTPUT_FILE_NAME", std::to_string(getpid()));
std::pair<std::ostream*, void (*)(std::ostream*&)>
get_output_stream(const std::string& fname, const std::string& ext = ".csv")
{
if(output_path.string().empty()) return {&std::clog, [](auto*&) {}};
if(fs::exists(output_path) && !fs::is_directory(fs::status(output_path)))
throw std::runtime_error{
fmt::format("ROCPROFILER_OUTPUT_PATH ({}) already exists and is not a directory",
output_path.string())};
if(!fs::exists(output_path)) fs::create_directories(output_path);
auto output_file = output_path / (output_file_name + "_" + fname + ext);
auto* _ofs = new std::ofstream{output_file};
if(!_ofs && !*_ofs)
throw std::runtime_error{fmt::format("Failed to open {} for output", output_file.string())};
std::cout << "Results File: " << output_file << std::endl;
return {_ofs, [](std::ostream*& v) {
if(v) dynamic_cast<std::ofstream*>(v)->close();
delete v;
v = nullptr;
}};
}
template <typename Tp>
std::string
as_hex(Tp _v, size_t _width = 16)
{
auto _ss = std::stringstream{};
_ss.fill('0');
_ss << "0x" << std::hex << std::setw(_width) << _v;
return _ss.str();
}
} // namespace
struct output_file
{
output_file(std::string name, std::vector<std::string>&& header)
: m_name{std::move(name)}
{
std::tie(m_stream, m_dtor) = get_output_stream(m_name);
auto ss = std::stringstream{};
for(auto&& itr : header)
{
ss << "," << itr;
}
// write the csv header
if(!ss.str().empty()) *m_stream << ss.str().substr(1) << '\n';
}
~output_file() { m_dtor(m_stream); }
output_file(const output_file&) = delete;
output_file& operator=(const output_file&) = delete;
std::string name() const { return m_name; }
template <typename T>
std::ostream& operator<<(T&& value)
{
return (*m_stream) << std::forward<T>(value);
}
std::ostream& operator<<(std::ostream& (*func)(std::ostream&) ) { return (*m_stream) << func; }
operator bool() const { return m_stream != nullptr; }
private:
using stream_dtor_t = void (*)(std::ostream*&);
const std::string m_name = {};
std::ostream* m_stream = nullptr;
stream_dtor_t m_dtor = [](std::ostream*&) {};
};
{} // namespace
auto&
get_hsa_api_file()
{
static auto _v =
output_file{"hsa_api_trace",
{"DOMAIN", "FUNCTION", "START_TIMESTAMP", "END_TIMESTAMP", "CORRELATION_ID"}};
static auto _v = tool::output_file{"hsa_api_trace",
tool::csv::hsa_csv_encoder{},
{"Domain",
"Function",
"Process_Id",
"Thread_Id",
"Correlation_Id",
"Start_Timestamp",
"End_Timestamp"}};
return _v;
}
auto&
get_kernel_trace_file()
{
static auto _v = output_file{"kernel_trace",
{"AGENT_ID",
"QUEUE_ID",
"KERNEL_ID",
"KERNEL_NAME",
"CONTEXT_ID",
"BUFFER_ID",
"CORRELATION_ID",
"KIND",
"START_TS",
"END_TS",
"PRIVATE_SEGMENT_SIZE",
"GROUP_SEGMENT_SIZE",
"WORKGROUP_SIZE_X",
"WORKGROUP_SIZE_Y",
"WORKGROUP_SIZE_Z",
"GRID_SIZE_X",
"GRID_SIZE_Y",
"GRID_SIZE_Z"}};
static auto _v = tool::output_file{"kernel_trace",
tool::csv::kernel_trace_csv_encoder{},
{"Kind",
"Agent_Id",
"Queue_Id",
"Kernel_Id",
"Kernel_Name",
"Correlation_Id",
"Start_Timestamp",
"End_Timestamp",
"Private_Segment_Size",
"Group_Segment_Size",
"Workgroup_Size_X",
"Workgroup_Size_Y",
"Workgroup_Size_Z",
"Grid_Size_X",
"Grid_Size_Y",
"Grid_Size_Z"}};
return _v;
}
std::shared_mutex kernel_data_mutex;
std::unordered_map<rocprofiler_kernel_id_t, std::string> kernel_data;
struct hsa_api_trace_entry_t
auto&
get_counter_collection_file()
{
std::atomic<uint32_t> valid;
rocprofiler_callback_tracing_record_t record;
rocprofiler_timestamp_t begin_timestamp;
rocprofiler_timestamp_t end_timestamp;
std::string_view api_name;
static auto _v = tool::output_file{"counter_collection",
tool::csv::counter_collection_csv_encoder{},
{"Counter_Id",
"Agent_Id",
"Queue_Id",
"Process_Id",
"Thread_Id",
"Grid_Size",
"Kernel-Name",
"Workgroup_Size",
"LDS_Block_Size",
"Scratch_Size",
"VGPR_Count",
"SGPR_Count",
"Counter_Name",
"Counter_Value"}};
return _v;
}
hsa_api_trace_entry_t(rocprofiler_timestamp_t begin,
rocprofiler_timestamp_t end,
rocprofiler_callback_tracing_record_t tracer_record,
std::string_view name)
: valid(TRACE_ENTRY_INIT)
, record(tracer_record)
, begin_timestamp(begin)
, end_timestamp(end)
, api_name(name)
auto&
get_memory_copy_trace_file()
{
static auto _v = tool::output_file{"memory_copy_trace",
tool::csv::memory_copy_csv_encoder{},
{"Kind",
"Direction",
"Source_Agent_Id",
"Destination_Agent_Id",
"Correlation_Id",
"Start_Timestamp",
"End_Timestamp"}};
return _v;
}
rocprofiler_buffer_id_t&
get_hsa_api_trace_buffer()
{
static rocprofiler_buffer_id_t hsa_api_buf = {};
return hsa_api_buf;
}
rocprofiler_buffer_id_t&
get_kernel_trace_buffer()
{
static rocprofiler_buffer_id_t kernel_trace_buf = {};
return kernel_trace_buf;
}
rocprofiler_buffer_id_t&
get_counter_collection_buffer()
{
static rocprofiler_buffer_id_t counter_collection_buf = {};
return counter_collection_buf;
}
rocprofiler_buffer_id_t&
get_memory_copy_trace_buffer()
{
static rocprofiler_buffer_id_t memory_copy_buf = {};
return memory_copy_buf;
}
using rocprofiler_kernel_symbol_data_t =
rocprofiler_callback_tracing_code_object_kernel_symbol_register_data_t;
struct kernel_symbol_data : rocprofiler_kernel_symbol_data_t
{
using base_type = rocprofiler_kernel_symbol_data_t;
kernel_symbol_data(const base_type& _base)
: base_type{_base}
, formatted_kernel_name{tool::format_name(CHECK_NOTNULL(_base.kernel_name))}
, demangled_kernel_name{common::cxx_demangle(CHECK_NOTNULL(_base.kernel_name))}
, truncated_kernel_name{common::truncate_name(demangled_kernel_name)}
{}
std::string formatted_kernel_name = {};
std::string demangled_kernel_name = {};
std::string truncated_kernel_name = {};
};
TraceBuffer<hsa_api_trace_entry_t> hsa_api_buffer("HSA API",
0x200000,
[](hsa_api_trace_entry_t* entry) {
TracerFlushRecord(
entry,
ROCPROFILER_CALLBACK_TRACING_HSA_API);
});
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>{};
auto name_info = get_buffer_id_names();
rocprofiler_tool_callback_name_info_t name_info;
auto&
get_client_ctx()
{
static rocprofiler_context_id_t context_id;
return context_id;
}
void
TracerFlushRecord(void* data, rocprofiler_callback_tracing_kind_t kind)
flush()
{
if(kind == ROCPROFILER_CALLBACK_TRACING_HSA_API)
for(auto itr : {get_memory_copy_trace_buffer(),
get_kernel_trace_buffer(),
get_counter_collection_buffer(),
get_hsa_api_trace_buffer()})
{
auto* entry = reinterpret_cast<hsa_api_trace_entry_t*>(data);
get_hsa_api_file() << "ACTIVITY_DOMAIN_HSA_API"
<< ","
<< "\"" << entry->api_name << "\""
<< "," << entry->begin_timestamp << "," << entry->end_timestamp << ","
<< entry->record.correlation_id.internal << '\n';
if(itr.handle > 0) ROCPROFILER_CALL(rocprofiler_flush_buffer(itr), "buffer flush");
}
}
@@ -214,35 +208,11 @@ rocprofiler_tracing_callback(rocprofiler_callback_tracing_record_t record,
rocprofiler_user_data_t* user_data,
void* data)
{
if(record.kind == ROCPROFILER_CALLBACK_TRACING_HIP_API)
{
// To be implemented
throw std::runtime_error{"not implemented"};
}
throw std::runtime_error{"not implemented"};
else if(record.kind == ROCPROFILER_CALLBACK_TRACING_HSA_API)
{
auto timestamp = rocprofiler_timestamp_t{};
ROCPROFILER_CALL(rocprofiler_get_timestamp(&timestamp), "timestamp failed");
if(record.phase == ROCPROFILER_CALLBACK_PHASE_ENTER)
{
user_data->value = timestamp;
}
else if(record.phase == ROCPROFILER_CALLBACK_PHASE_EXIT)
{
const auto* info_name_str = name_info.operation_names[record.kind][record.operation];
hsa_api_trace_entry_t& entry =
hsa_api_buffer.Emplace(user_data->value, timestamp, record, info_name_str);
entry.valid.store(TRACE_ENTRY_COMPLETE, std::memory_order_release);
}
}
else if(record.kind == ROCPROFILER_CALLBACK_TRACING_MARKER_API)
{
// To be implemented
throw std::runtime_error{"not implemented"};
}
(void) (data);
(void) record;
(void) user_data;
(void) data;
}
void
@@ -255,38 +225,22 @@ code_object_tracing_callback(rocprofiler_callback_tracing_record_t record,
{
if(record.phase == ROCPROFILER_CALLBACK_PHASE_UNLOAD)
{
// flush the buffer to ensure that any lookups for the client kernel names for the code
// object are completed
auto flush_status = rocprofiler_flush_buffer(tool_buffer);
if(flush_status != ROCPROFILER_STATUS_ERROR_BUFFER_BUSY)
ROCPROFILER_CALL(flush_status, "buffer flush");
flush();
}
}
if(record.kind == ROCPROFILER_CALLBACK_TRACING_CODE_OBJECT &&
record.operation == ROCPROFILER_CALLBACK_TRACING_CODE_OBJECT_DEVICE_KERNEL_SYMBOL_REGISTER)
{
auto* sym_data =
static_cast<rocprofiler_callback_tracing_code_object_kernel_symbol_register_data_t*>(
record.payload);
auto* sym_data = static_cast<rocprofiler_kernel_symbol_data_t*>(record.payload);
if(record.phase == ROCPROFILER_CALLBACK_PHASE_LOAD)
{
auto kernel_name =
std::regex_replace(sym_data->kernel_name, std::regex{"(\\.kd)$"}, "");
int demangle_status = 0;
kernel_name = cxa_demangle(kernel_name, &demangle_status);
std::unique_lock<std::shared_mutex> lock(kernel_data_mutex);
kernel_data.emplace(sym_data->kernel_id, kernel_name);
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});
},
sym_data);
}
// The map entry cannot be erased here
// since we are tracing the kernel symbols here not the kernel dispatch
// else if(record.phase == ROCPROFILER_CALLBACK_PHASE_UNLOAD)
//{
// kernel_data.erase(data->kernel_id);
//}
}
(void) user_data;
@@ -294,174 +248,369 @@ code_object_tracing_callback(rocprofiler_callback_tracing_record_t record,
}
void
kernel_tracing_callback(rocprofiler_context_id_t context,
rocprofiler_buffer_id_t buffer_id,
rocprofiler_record_header_t** headers,
size_t num_headers,
void* user_data,
uint64_t /*drop_count*/)
buffered_callback(rocprofiler_context_id_t /*context*/,
rocprofiler_buffer_id_t /*buffer_id*/,
rocprofiler_record_header_t** headers,
size_t num_headers,
void* /*user_data*/,
uint64_t /*drop_count*/)
{
static auto _sync = std::mutex{};
auto _lk = std::lock_guard<std::mutex>{_sync};
if(num_headers == 0)
throw std::runtime_error{
"rocprofiler invoked a buffer callback with no headers. this should never happen"};
throw std::runtime_error{"rocprofiler invoked a buffer callback with no headers "
"this should never happen"};
else if(headers == nullptr)
throw std::runtime_error{"rocprofiler invoked a buffer callback with a null pointer to the "
"array of headers. this should never happen"};
auto kernel_trace_ss = std::stringstream{};
for(size_t i = 0; i < num_headers; ++i)
{
auto* header = headers[i];
if(header == nullptr)
if(header->category == ROCPROFILER_BUFFER_CATEGORY_TRACING)
{
throw std::runtime_error{
"rocprofiler provided a null pointer to header. this should never happen"};
}
else if(header->hash !=
rocprofiler_record_header_compute_hash(header->category, header->kind))
{
throw std::runtime_error{"rocprofiler_record_header_t (category | kind) != hash"};
}
else if(header->category == ROCPROFILER_BUFFER_CATEGORY_TRACING &&
header->kind == ROCPROFILER_BUFFER_TRACING_KERNEL_DISPATCH)
{
auto* record =
static_cast<rocprofiler_buffer_tracing_kernel_dispatch_record_t*>(header->payload);
std::string kernel_name;
if(header->kind == ROCPROFILER_BUFFER_TRACING_KERNEL_DISPATCH)
{
std::shared_lock<std::shared_mutex> lock(kernel_data_mutex);
kernel_name = kernel_data.at(record->kernel_id);
}
auto* record = static_cast<rocprofiler_buffer_tracing_kernel_dispatch_record_t*>(
header->payload);
std::string kernel_name = kernel_data.rlock(
[](const kernel_symbol_data_map_t& kdata,
rocprofiler_buffer_tracing_kernel_dispatch_record_t* record_v) {
return kdata.at(record_v->kernel_id).formatted_kernel_name;
},
record);
kernel_trace_ss << record->agent_id.handle << "," << record->queue_id.handle << ","
<< record->kernel_id << ",\"" << kernel_name << "\"," << context.handle
<< "," << buffer_id.handle << "," << record->correlation_id.internal
<< "," << record->kind << "," << record->start_timestamp << ","
<< record->end_timestamp << "," << record->private_segment_size << ","
<< record->group_segment_size << "," << record->workgroup_size.x << ","
<< record->workgroup_size.y << "," << record->workgroup_size.z << ","
<< record->grid_size.x << "," << record->grid_size.y << ","
<< record->grid_size.z << '\n';
auto kernel_trace_ss = std::stringstream{};
tool::csv::kernel_trace_csv_encoder::write_row(
kernel_trace_ss,
name_info.kind_names.at(record->kind),
record->agent_id.handle,
record->queue_id.handle,
record->kernel_id,
std::move(kernel_name),
record->correlation_id.internal,
record->start_timestamp,
record->end_timestamp,
record->private_segment_size,
record->group_segment_size,
record->workgroup_size.x,
record->workgroup_size.y,
record->workgroup_size.z,
record->grid_size.x,
record->grid_size.y,
record->grid_size.z);
get_kernel_trace_file() << kernel_trace_ss.str();
}
else if(header->kind == ROCPROFILER_BUFFER_TRACING_HSA_API)
{
auto* record =
static_cast<rocprofiler_buffer_tracing_hsa_api_record_t*>(header->payload);
auto hsa_trace_ss = std::stringstream{};
tool::csv::hsa_csv_encoder::write_row(
hsa_trace_ss,
name_info.kind_names.at(record->kind),
name_info.operation_names.at(record->kind).at(record->operation),
getpid(),
record->thread_id,
record->correlation_id.internal,
record->start_timestamp,
record->end_timestamp);
get_hsa_api_file() << hsa_trace_ss.str();
}
else if(header->kind == ROCPROFILER_BUFFER_TRACING_MEMORY_COPY)
{
auto* record =
static_cast<rocprofiler_buffer_tracing_memory_copy_record_t*>(header->payload);
auto memory_copy_trace_ss = std::stringstream{};
tool::csv::memory_copy_csv_encoder::write_row(
memory_copy_trace_ss,
name_info.kind_names.at(record->kind),
name_info.operation_names.at(record->kind).at(record->operation),
record->src_agent_id.handle,
record->dst_agent_id.handle,
record->correlation_id.internal,
record->start_timestamp,
record->end_timestamp);
get_memory_copy_trace_file() << memory_copy_trace_ss.str();
}
else
{
LOG(FATAL) << fmt::format(
"unsupported category + kind: {} + {}", header->category, header->kind);
}
}
if(header->category == ROCPROFILER_BUFFER_CATEGORY_COUNTERS && header->kind == 0)
{
auto* profiler_record = static_cast<rocprofiler_record_counter_t*>(header->payload);
rocprofiler_tool_kernel_properties_t kernel_properties =
GetKernelProperties(profiler_record->corr_id.internal);
rocprofiler_counter_id_t counter_id;
const char* counter_name;
size_t size, pos;
rocprofiler_query_record_counter_id(profiler_record->id, &counter_id);
rocprofiler_query_counter_name(counter_id, &counter_name, &size);
rocprofiler_query_record_dimension_position(profiler_record->id, 0, &pos);
auto counter_collection_ss = std::stringstream{};
counter_collection_ss << counter_id.handle << ","
<< kernel_properties.gpu_agent.id.handle << ","
<< kernel_properties.queue_id.handle << "," << getpid() << ","
<< kernel_properties.thread_id << ",";
counter_collection_ss << 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 << ",";
/*
Iterate through the N dimensional that is obtained for the counter.
given instance id what is the counter id
given counter id what is the counter name
given instance how many dimension
iterate through dimensions
what is the dimension id
what is the dimension name
what pos in the dimension.
*/
// ss << counter_name << "[" << info.name << "," << pos << "]" << ",";
// ss << profiler_record->counter_value << "\n";
counter_collection_ss << counter_name << "["
<< "," << pos << "]"
<< ",";
counter_collection_ss << counter_name << ",";
counter_collection_ss << profiler_record->counter_value << "\n";
get_counter_collection_file() << counter_collection_ss.str() << "\n";
}
}
static auto _sync = std::mutex{};
auto _lk = std::unique_lock<std::mutex>{_sync};
if(get_kernel_trace_file())
get_kernel_trace_file() << kernel_trace_ss.str();
else
std::cerr << "kernel trace file already closed: " << kernel_trace_ss.str();
(void) (user_data);
}
rocprofiler_tool_callback_name_info_t
get_callback_id_names()
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>>;
// this function creates a rocprofiler profile config on the first entry
auto
get_agent_profile(const rocprofiler_agent_t* agent)
{
auto cb_name_info = rocprofiler_tool_callback_name_info_t{};
//
// callback for each kind operation
//
static auto tracing_kind_operation_cb =
[](rocprofiler_callback_tracing_kind_t kindv, uint32_t operation, void* data_v) {
auto* name_info_v = static_cast<rocprofiler_tool_callback_name_info_t*>(data_v);
static auto data = common::Synchronized<agent_counter_map_t>{};
if(kindv == ROCPROFILER_CALLBACK_TRACING_HSA_API)
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);
if(itr != data_v.end())
{
const char* name = nullptr;
ROCPROFILER_CALL(rocprofiler_query_callback_tracing_kind_operation_name(
kindv, operation, &name, nullptr),
"query callback failed");
if(name) name_info_v->operation_names[kindv][operation] = name;
profile = itr->second;
return true;
}
return false;
},
[agent, &profile](agent_counter_map_t& data_v) {
auto counters_v = counter_vec_t{};
ROCPROFILER_CALL(
rocprofiler_iterate_agent_supported_counters(
*agent,
[](rocprofiler_counter_id_t* counters, size_t num_counters, void* user_data) {
auto* vec = static_cast<counter_vec_t*>(user_data);
for(size_t i = 0; i < num_counters; i++)
{
const char* name = nullptr;
size_t len = 0;
ROCPROFILER_CALL(
rocprofiler_query_counter_name(counters[i], &name, &len),
"Could not query name");
if(name && len > 0)
{
if(tool::get_config().counters.count(name) > 0)
vec->emplace_back(counters[i]);
}
}
return ROCPROFILER_STATUS_SUCCESS;
},
static_cast<void*>(&counters_v)),
"iterate agent supported counters");
if(!counters_v.empty())
{
auto profile_v = rocprofiler_profile_config_id_t{};
ROCPROFILER_CALL(rocprofiler_create_profile_config(
*agent, counters_v.data(), counters_v.size(), &profile_v),
"Could not construct profile cfg");
profile = profile_v;
}
if(kindv == ROCPROFILER_CALLBACK_TRACING_HIP_API)
{
const char* name = nullptr;
ROCPROFILER_CALL(rocprofiler_query_callback_tracing_kind_operation_name(
kindv, operation, &name, nullptr),
"query callback failed");
if(name) name_info_v->operation_names[kindv][operation] = name;
}
return 0;
};
data_v.emplace(agent, profile);
return true;
});
//
// callback for each callback kind (i.e. domain)
//
static auto tracing_kind_cb = [](rocprofiler_callback_tracing_kind_t kind, void* data) {
// store the callback kind name
auto* name_info_v = static_cast<rocprofiler_tool_callback_name_info_t*>(data);
const char* name = nullptr;
ROCPROFILER_CALL(rocprofiler_query_callback_tracing_kind_name(kind, &name, nullptr),
"query callback failed");
return profile;
}
if(name) name_info_v->kind_names[kind] = name;
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);
if(kind == ROCPROFILER_CALLBACK_TRACING_HSA_API)
auto is_targeted_kernel = [&kernel_info]() {
for(const auto& name : tool::get_config().kernel_names)
{
ROCPROFILER_CALL(rocprofiler_iterate_callback_tracing_kind_operations(
kind, tracing_kind_operation_cb, static_cast<void*>(data)),
"query callback failed");
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 0;
return false;
};
ROCPROFILER_CALL(rocprofiler_iterate_callback_tracing_kinds(tracing_kind_cb,
static_cast<void*>(&cb_name_info)),
"iterate_callback failed");
if(!is_targeted_kernel()) return;
return cb_name_info;
auto profile = get_agent_profile(agent);
if(profile)
{
kernel_properties.kernel_name = kernel_info.formatted_kernel_name;
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;
int
tool_init(rocprofiler_client_finalize_t /*fini_func*/, void* tool_data)
tool_init(rocprofiler_client_finalize_t fini_func, void* tool_data)
{
name_info = get_callback_id_names();
client_finalizer = fini_func;
ROCPROFILER_CALL(rocprofiler_create_context(&context_id), "create context failed");
ROCPROFILER_CALL(rocprofiler_create_context(&get_client_ctx()), "create context failed");
if(common::get_env("ROCPROFILER_KERNEL_TRACE", false))
ROCPROFILER_CALL(
rocprofiler_configure_callback_tracing_service(get_client_ctx(),
ROCPROFILER_CALLBACK_TRACING_CODE_OBJECT,
nullptr,
0,
code_object_tracing_callback,
nullptr),
"code object tracing configure failed");
if(tool::get_config().kernel_trace)
{
ROCPROFILER_CALL(
rocprofiler_configure_callback_tracing_service(context_id,
ROCPROFILER_CALLBACK_TRACING_CODE_OBJECT,
nullptr,
0,
code_object_tracing_callback,
nullptr),
"tracing configure failed");
ROCPROFILER_CALL(rocprofiler_create_buffer(context_id,
ROCPROFILER_CALL(rocprofiler_create_buffer(get_client_ctx(),
4096,
2048,
ROCPROFILER_BUFFER_POLICY_LOSSLESS,
kernel_tracing_callback,
buffered_callback,
tool_data,
&tool_buffer),
&get_kernel_trace_buffer()),
"buffer creation");
ROCPROFILER_CALL(
rocprofiler_configure_buffer_tracing_service(
context_id, ROCPROFILER_BUFFER_TRACING_KERNEL_DISPATCH, nullptr, 0, tool_buffer),
rocprofiler_configure_buffer_tracing_service(get_client_ctx(),
ROCPROFILER_BUFFER_TRACING_KERNEL_DISPATCH,
nullptr,
0,
get_kernel_trace_buffer()),
"buffer tracing service for kernel dispatch configure");
}
if(common::get_env("ROCPROFILER_HSA_API_TRACE", false))
if(tool::get_config().memory_copy_trace)
{
// Requesting all operations
ROCPROFILER_CALL(rocprofiler_create_buffer(get_client_ctx(),
4096,
2048,
ROCPROFILER_BUFFER_POLICY_LOSSLESS,
buffered_callback,
nullptr,
&get_memory_copy_trace_buffer()),
"create memory copy buffer");
ROCPROFILER_CALL(
rocprofiler_configure_callback_tracing_service(context_id,
ROCPROFILER_CALLBACK_TRACING_HSA_API,
nullptr,
0,
rocprofiler_tracing_callback,
nullptr),
"tracing configure failed");
rocprofiler_configure_buffer_tracing_service(get_client_ctx(),
ROCPROFILER_BUFFER_TRACING_MEMORY_COPY,
nullptr,
0,
get_memory_copy_trace_buffer()),
"buffer tracing service for memory copy configure");
}
ROCPROFILER_CALL(rocprofiler_start_context(context_id), "start context failed");
if(tool::get_config().hsa_api_trace)
{
ROCPROFILER_CALL(rocprofiler_create_buffer(get_client_ctx(),
4096,
2048,
ROCPROFILER_BUFFER_POLICY_LOSSLESS,
buffered_callback,
tool_data,
&get_hsa_api_trace_buffer()),
"buffer creation");
ROCPROFILER_CALL(
rocprofiler_configure_buffer_tracing_service(get_client_ctx(),
ROCPROFILER_BUFFER_TRACING_HSA_API,
nullptr,
0,
get_hsa_api_trace_buffer()),
"buffer tracing service for memory copy configure");
}
if(tool::get_config().counter_collection)
{
ROCPROFILER_CALL(rocprofiler_create_buffer(get_client_ctx(),
4096,
2048,
ROCPROFILER_BUFFER_POLICY_LOSSLESS,
buffered_callback,
nullptr,
&get_counter_collection_buffer()),
"buffer creation failed");
ROCPROFILER_CALL(
rocprofiler_configure_buffered_dispatch_profile_counting_service(
get_client_ctx(), get_counter_collection_buffer(), dispatch_callback, nullptr),
"Could not setup buffered service");
}
ROCPROFILER_CALL(rocprofiler_start_context(get_client_ctx()), "start context failed");
std::atexit([]() {
if(client_finalizer && client_identifier) client_finalizer(*client_identifier);
});
return 0;
}
@@ -469,8 +618,12 @@ tool_init(rocprofiler_client_finalize_t /*fini_func*/, void* tool_data)
void
tool_fini(void* tool_data)
{
rocprofiler_flush_buffer(tool_buffer);
rocprofiler_stop_context(context_id);
client_identifier = nullptr;
client_finalizer = nullptr;
flush();
rocprofiler_stop_context(get_client_ctx());
(void) (tool_data);
}
@@ -480,14 +633,17 @@ rocprofiler_configure(uint32_t /*version*/,
uint32_t priority,
rocprofiler_client_id_t* id)
{
common::init_logging("ROCPROF_LOG_LEVEL");
FLAGS_colorlogtostderr = true;
// only activate if main tool
if(priority > 0) return nullptr;
// set the client name
id->name = "rocporfiler-tool";
id->name = "rocprofiler-tool";
// store client info
// client::client_id = id;
client_identifier = id;
// create configure data
static auto cfg = rocprofiler_tool_configure_result_t{