[rocprofv3-benchmark] SDK and rocprofv3 Benchmarking Suite (#157)

* Adding Benchmarking Stg1

* config fix

* reset

* add jpeg and decode traces in iteration

* address comments benchmark config files.

* address comments.

* address comments.

* address comments: revert cntrl ctx.

* address comments: revert csv output.

* resolve merge conflits.

* format.

* build fix.

* fix hip runtime api traces.

* loop cb services.

* format.

* bug fix.

* Fix operator>

- public C++ comparison operator

* Update configuration options

- support selected regions (--selected-regions)
- support writing output config json (--output-config)
- update serialization data

* rocprofv3 tool library misc updates

- lambda for starting context
- support for writing config json

* Tool library updates

- Finished support for all benchmarking modes
- Added build spec support to config json

* Fix ROCPROFILER_SOVERSION

- this value should not be multiplied by 10,000

* Minor tweak to rocprofv3

* Benchmarking scripts

* formatting

* Fix duplicate include

* Add reproducible-dispatch-count test app

- used in benchmarking

* registration logging

- report number of registered contexts and active contexts after client initialization

* Serialize environment in rocprofv3 output config

* ROCPROFILER_BUILD_BENCHMARK CMake option

* Update benchmark SQL schema

- hash_id is text
- add md5sum to benchmarked_app
- remove app_id from benchmarked_sdk
- add sdk_id to benchmark_config
- separate hip_trace into hip_runtime_trace and hip_compiler_trace
- use INT instead of INTEGER for MySQL compatibility
- add count column in benchmark_statistics
- allow std_dev to be NULL in benchmark_statistics

* Update rocprofv3-benchmark.py

- use md5 instead of python hash (which includes random seed)
- use args.mysql_database
- compute md5sum of executable
- fix insert_benchmark_config
  - marker trace fixes
  - memory allocation fixes
  - split hip_trace into hip_{runtime,compiler}_trace
- remove app_id from benchmarked_sdk
- support warmup runs
- count field in benchmark_statistics

* Support launcher and environment in YAML

* Update reproducible-dispatch-count.cpp

- support mode which doesn't use hip event timing

* Misc rocprofv3-benchmark.py updates

- fix some MySQL support
- remove some unnecessary logging

* support mysql db.

* Format.

* Updated SQL input files

- moved benchmark_schema.sql to benchmark_table.sql
- added benchmark_views.sql
  - uses {{metric}} syntax for variable substitution

* cmake formatting

* update rocprofv3-benchmark.py

- benchmark config labels
- overhead views

* Encode rocprofv3-benchmark PID in rocprofv3 and timem output files

* Minor tweak to benchmark_views.sql

- include count
- reorder fields for readability

* split statements and use IS if values is NONE.

* use backtick instead of double quotes and add IS before NOT NULL.:

* Adding Mandelbrot Benchmark App

* Adding Dockerfile example

* Update dockerfile

* Update dockerfile

* [SDK] rocprofiler_query_external_correlation_id_request_kind_name

* Execution-profile benchmark mode

* Execution profile SQL support

* Rename mandlebrot folder + misc clang-tidy

* [rocprofv3-benchmark] Execution profile support

* Update installation

* add work dir when setting git revision, useful when building outside src.

* Set FULL_VERSION_STRING and ROCPROFILER_SDK_GIT_REVISION

- when benchmark folder is top-level

* Remove unused python packages from requirements.txt

* Use ldd/pyelftools to include linked libs for md5sum

- also add --filter-benchmark and --filter-rocprofv3 options
- support labeling the rocprofv3 options
- use more argparse groups
- more generic application of filters
- support variable substitution in environment, e.g. PATH=/some/path:$PATH

* Environment improvements

- improve reproducibility when env set via input file vs. shell
- support "environment-ignore" to remove environment variables

* Misc formatting

* Misc. fix

* use backticks for defining new columns name

* Support shuffling the order of benchmark modes/rocprofv3 args

* Address review comments

* Update Dockerfile

- rename to Dockerfile
- reduce to one layer

* Support docker build arg BRANCH

---------

Co-authored-by: Ammar ELWazir <aelwazir@amd.com>
Co-authored-by: Kandula, Venkateshwar reddy <Venkateshwarreddy.Kandula@amd.com>
Co-authored-by: Venkateshwar Reddy Kandula <vkandula@amd.com>
Co-authored-by: Madsen, Jonathan <Jonathan.Madsen@amd.com>
Co-authored-by: Jonathan R. Madsen <jonathanrmadsen@gmail.com>
This commit is contained in:
Elwazir, Ammar
2025-05-13 16:18:23 -05:00
committed by GitHub
parent b297e72853
commit 6f17da7ade
43 changed files with 5206 additions and 280 deletions
+47
View File
@@ -248,6 +248,11 @@ For MPI applications (or other job launchers such as SLURM), place rocprofv3 ins
choices=("csv", "json", "pftrace", "otf2"),
type=str.lower,
)
add_parser_bool_argument(
io_options,
"--output-config",
help="Generate a output file of the rocprofv3 configuration, e.g. out_config.json",
)
io_options.add_argument(
"--log-level",
help="Set the desired log level",
@@ -518,6 +523,11 @@ For MPI applications (or other job launchers such as SLURM), place rocprofv3 ins
type=str,
choices=("hour", "min", "sec", "msec", "usec", "nsec"),
)
add_parser_bool_argument(
filter_options,
"--selected-regions",
help="If set, rocprofv3 will only profile regions of code surrounded by roctxProfilerResume(0) and roctxProfilerPause(0)",
)
perfetto_options = parser.add_argument_group("Perfetto-specific options")
@@ -592,6 +602,19 @@ For MPI applications (or other job launchers such as SLURM), place rocprofv3 ins
"--realpath",
help=argparse.SUPPRESS,
)
advanced_options.add_argument(
"--benchmark-mode",
choices=(
"disabled-sdk-contexts",
"sdk-buffer-overhead",
"sdk-callback-overhead",
"tool-runtime-overhead",
"execution-profile",
),
help=argparse.SUPPRESS,
default=None,
type=str.lower,
)
advanced_options.add_argument(
"-A",
"--agent-index",
@@ -1034,6 +1057,7 @@ def run(app_args, args, **kwargs):
update_env("ROCPROF_OUTPUT_FILE_NAME", _output_file)
update_env("ROCPROF_OUTPUT_PATH", _output_path)
update_env("ROCPROF_OUTPUT_CONFIG_FILE", args.output_config, overwrite_if_true=True)
if app_pass is not None and args.sub_directory is not None:
app_env["ROCPROF_OUTPUT_PATH"] = os.path.join(
f"{_output_path}", f"{args.sub_directory}{app_pass}"
@@ -1198,6 +1222,11 @@ def run(app_args, args, **kwargs):
args.truncate_kernels,
overwrite_if_true=True,
)
update_env(
"ROCPROF_SELECTED_REGIONS",
args.selected_regions,
overwrite_if_true=True,
)
if args.list_avail:
update_env(
@@ -1241,6 +1270,24 @@ def run(app_args, args, **kwargs):
args.log_level,
)
if args.benchmark_mode:
if args.benchmark_mode == "execution-profile":
if args.group_by_queue is None:
update_env(
"ROCPROF_GROUP_BY_QUEUE",
False,
overwrite=True,
)
elif args.group_by_queue:
fatal_error(
"rocprofv3 requires --group-by-queue=false for --benchmark-mode=execution-profile"
)
update_env(
"ROCPROF_BENCHMARK_MODE",
args.benchmark_mode,
)
for opt, env_val in dict(
[
["kernel_rename", "KERNEL_RENAME"],
+1 -1
View File
@@ -46,4 +46,4 @@ To run the built samples, ``cd`` into the ``build-rocprofiler-sdk-samples`` dire
ctest -V
The `-V` option enables verbose output, providing detailed information about the test execution.
The `-V` option enables verbose output, providing detailed information about the test execution.
+1 -1
View File
@@ -126,4 +126,4 @@ If you have ROCm version 6.2 or higher installed, you can use the package manage
.. code-block:: shell
$ sudo zypper install rocprofiler-sdk
$ sudo zypper install rocprofiler-sdk
@@ -55,7 +55,7 @@
}
#define ROCPROFILER_CXX_DEFINE_COMPARE_OPERATORS(TYPE) \
inline bool operator>(TYPE lhs, TYPE rhs) { return (lhs == rhs || !(lhs < rhs)); } \
inline bool operator>(TYPE lhs, TYPE rhs) { return !(lhs == rhs || lhs < rhs); } \
inline bool operator<=(TYPE lhs, TYPE rhs) { return (lhs == rhs || lhs < rhs); } \
inline bool operator>=(TYPE lhs, TYPE rhs) { return !(lhs < rhs); }
@@ -135,6 +135,29 @@ rocprofiler_configure_external_correlation_id_request_service(
rocprofiler_external_correlation_id_request_cb_t callback,
void* callback_args) ROCPROFILER_API ROCPROFILER_NONNULL(4);
/**
* @brief Query the name of the external correlation request kind. The name retrieved from this
* function is a string literal that is encoded in the read-only section of the binary (i.e. it is
* always "allocated" and never "deallocated").
*
* @param [in] kind External correlation id request domain
* @param [out] name If non-null and the name is a constant string that does not require dynamic
* allocation, this paramter will be set to the address of the string literal, otherwise it will
* be set to nullptr
* @param [out] name_len If non-null, this will be assigned the length of the name (regardless of
* the name is a constant string or requires dynamic allocation)
* @return ::rocprofiler_status_t
* @retval ::ROCPROFILER_STATUS_ERROR_KIND_NOT_FOUND Returned if the domain id is not valid
* @retval ::ROCPROFILER_STATUS_SUCCESS Returned if a valid domain, regardless if there is a
* constant string or not.
*/
ROCPROFILER_SDK_EXPERIMENTAL
rocprofiler_status_t
rocprofiler_query_external_correlation_id_request_kind_name(
rocprofiler_external_correlation_id_request_kind_t kind,
const char** name,
uint64_t* name_len) ROCPROFILER_API;
/**
* @brief Push default value for `external` field in ::rocprofiler_correlation_id_t onto stack.
*
+1 -1
View File
@@ -94,7 +94,7 @@
#define ROCPROFILER_VERSION_MAJOR @PROJECT_VERSION_MAJOR@
#define ROCPROFILER_VERSION_MINOR @PROJECT_VERSION_MINOR@
#define ROCPROFILER_VERSION_PATCH @PROJECT_VERSION_PATCH@
#define ROCPROFILER_SOVERSION (10000 * @PROJECT_VERSION_MAJOR@)
#define ROCPROFILER_SOVERSION @PROJECT_VERSION_MAJOR@
#define ROCPROFILER_VERSION_STRING "@FULL_VERSION_STRING@"
#define ROCPROFILER_GIT_DESCRIBE "@ROCPROFILER_SDK_GIT_DESCRIBE@"
#define ROCPROFILER_GIT_REVISION "@ROCPROFILER_SDK_GIT_REVISION@"
+1
View File
@@ -130,6 +130,7 @@ output_config::save(ArchiveT& ar) const
CFG_SERIALIZE_MEMBER(otf2_output);
CFG_SERIALIZE_MEMBER(summary_output);
CFG_SERIALIZE_MEMBER(kernel_rename);
CFG_SERIALIZE_MEMBER(group_by_queue);
#undef CFG_SERIALIZE_MEMBER
#undef CFG_SERIALIZE_NAMED_MEMBER
@@ -4,7 +4,7 @@
rocprofiler_activate_clang_tidy()
set(TOOL_HEADERS config.hpp helper.hpp stream_stack.hpp)
set(TOOL_HEADERS config.hpp execution_profile.hpp helper.hpp stream_stack.hpp)
set(TOOL_SOURCES config.cpp main.c tool.cpp stream_stack.cpp)
@@ -319,6 +319,23 @@ config::config()
std::stoull(_config_params.at(2))});
}
}
// Benchmarking Enable/Disable
if(!benchmark_mode_env.empty())
{
const auto valid_options = std::unordered_map<std::string_view, config::benchmark>{
{"disabled-sdk-contexts", benchmark::disabled_contexts_overhead},
{"sdk-buffer-overhead", benchmark::sdk_buffered_overhead},
{"sdk-callback-overhead", benchmark::sdk_callback_overhead},
{"tool-runtime-overhead", benchmark::tool_runtime_overhead},
{"execution-profile", benchmark::execution_profile},
};
ROCP_FATAL_IF(valid_options.count(benchmark_mode_env) == 0)
<< fmt::format("Invalid value for ROCPROF_BENCHMARK_MODE: {}", benchmark_mode_env);
benchmark_mode = valid_options.at(benchmark_mode_env);
}
}
std::string
+29 -3
View File
@@ -87,6 +87,16 @@ struct config : output_config
void save(ArchiveT& ar) const;
};
enum class benchmark
{
none = 0,
disabled_contexts_overhead,
sdk_callback_overhead,
sdk_buffered_overhead,
tool_runtime_overhead,
execution_profile,
};
config();
~config() = default;
@@ -114,11 +124,13 @@ struct config : output_config
bool rocjpeg_api_trace = get_env("ROCPROF_ROCJPEG_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);
bool pc_sampling_host_trap = false;
bool advanced_thread_trace = get_env("ROCPROF_ADVANCED_THREAD_TRACE", false);
bool pc_sampling_stochastic = false;
bool att_serialize_all = get_env("ROCPROF_ATT_PARAM_SERIALIZE_ALL", false);
bool enable_signal_handlers = get_env("ROCPROF_SIGNAL_HANDLERS", true);
bool selected_regions = get_env("ROCPROF_SELECTED_REGIONS", false);
bool output_config_file = get_env("ROCPROF_OUTPUT_CONFIG_FILE", false);
bool pc_sampling_host_trap = false;
bool pc_sampling_stochastic = false;
size_t pc_sampling_interval = get_env("ROCPROF_PC_SAMPLING_INTERVAL", 1);
rocprofiler_pc_sampling_method_t pc_sampling_method_value = ROCPROFILER_PC_SAMPLING_METHOD_NONE;
rocprofiler_pc_sampling_unit_t pc_sampling_unit_value = ROCPROFILER_PC_SAMPLING_UNIT_NONE;
@@ -148,6 +160,9 @@ struct config : output_config
uint64_t counter_groups_interval = get_env("ROCPROF_COUNTER_GROUPS_INTERVAL", 1);
uint64_t minimum_output_bytes = get_env("ROCPROF_MINIMUM_OUTPUT_BYTES", 0);
std::string benchmark_mode_env = get_env("ROCPROF_BENCHMARK_MODE", "");
benchmark benchmark_mode = benchmark::none;
template <typename ArchiveT>
void save(ArchiveT&) const;
@@ -180,6 +195,8 @@ template <typename ArchiveT>
void
config::save(ArchiveT& ar) const
{
CFG_SERIALIZE_NAMED_MEMBER("benchmark_mode", benchmark_mode_env);
CFG_SERIALIZE_MEMBER(kernel_trace);
CFG_SERIALIZE_MEMBER(hsa_core_api_trace);
CFG_SERIALIZE_MEMBER(hsa_amd_ext_api_trace);
@@ -194,6 +211,7 @@ config::save(ArchiveT& ar) const
CFG_SERIALIZE_MEMBER(hip_compiler_api_trace);
CFG_SERIALIZE_MEMBER(rccl_api_trace);
CFG_SERIALIZE_MEMBER(rocdecode_api_trace);
CFG_SERIALIZE_MEMBER(rocjpeg_api_trace);
CFG_SERIALIZE_MEMBER(mpi_rank);
CFG_SERIALIZE_MEMBER(mpi_size);
@@ -207,7 +225,13 @@ config::save(ArchiveT& ar) const
CFG_SERIALIZE_MEMBER(truncate);
CFG_SERIALIZE_MEMBER(minimum_output_bytes);
CFG_SERIALIZE_MEMBER(enable_signal_handlers);
CFG_SERIALIZE_MEMBER(selected_regions);
CFG_SERIALIZE_MEMBER(counter_groups_random_seed);
CFG_SERIALIZE_MEMBER(counter_groups_interval);
CFG_SERIALIZE_MEMBER(pc_sampling_host_trap);
CFG_SERIALIZE_MEMBER(pc_sampling_stochastic);
CFG_SERIALIZE_MEMBER(pc_sampling_method);
CFG_SERIALIZE_MEMBER(pc_sampling_unit);
CFG_SERIALIZE_MEMBER(pc_sampling_interval);
@@ -222,8 +246,10 @@ config::save(ArchiveT& ar) const
CFG_SERIALIZE_MEMBER(att_param_target_cu);
CFG_SERIALIZE_MEMBER(att_capability);
CFG_SERIALIZE_MEMBER(att_param_perfcounters);
CFG_SERIALIZE_MEMBER(att_param_perf_ctrl);
static_cast<const base_type&>(*this).save(ar);
// serialize the base class
static_cast<const base_type*>(this)->save(ar);
}
#undef CFG_SERIALIZE_MEMBER
@@ -0,0 +1,104 @@
// MIT License
//
// Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#pragma once
#include "lib/output/metadata.hpp"
#include <rocprofiler-sdk/external_correlation.h>
#include <rocprofiler-sdk/fwd.h>
#include <rocprofiler-sdk/cxx/hash.hpp>
#include <rocprofiler-sdk/cxx/operators.hpp>
#include <cereal/cereal.hpp>
#include <algorithm>
#include <cstdint>
#include <map>
#include <unordered_map>
#include <unordered_set>
namespace rocprofiler
{
namespace tool
{
struct execution_profile_data
{
using extern_corr_id_request_t = rocprofiler_external_correlation_id_request_kind_t;
using operation_set_t = std::unordered_set<rocprofiler_tracing_operation_t>;
std::unordered_map<extern_corr_id_request_t, uint64_t> category_count = {};
std::unordered_map<extern_corr_id_request_t, operation_set_t> category_op_count = {};
std::unordered_set<rocprofiler_thread_id_t> threads = {};
std::unordered_set<rocprofiler_context_id_t> contexts = {};
};
struct execution_profile_category_data
{
uint64_t count = 0; // total invocations of a given category
uint64_t unique = 0; // number of unique operations
};
} // namespace tool
} // namespace rocprofiler
namespace cereal
{
template <typename ArchiveT>
void
save(ArchiveT& ar, ::rocprofiler::tool::execution_profile_category_data data)
{
ar(cereal::make_nvp("count", data.count));
ar(cereal::make_nvp("unique", data.unique));
}
template <typename ArchiveT>
void
save(ArchiveT& ar, const ::rocprofiler::tool::execution_profile_data& data)
{
namespace tool = ::rocprofiler::tool;
using category_count_map_t = std::map<std::string, tool::execution_profile_category_data>;
auto _category_count = category_count_map_t{};
for(auto itr : data.category_count)
{
const char* _name = nullptr;
ROCPROFILER_CHECK(rocprofiler_query_external_correlation_id_request_kind_name(
itr.first, &_name, nullptr));
if(_name)
{
auto _unique_ops = data.category_op_count.at(itr.first).size();
auto _kind_name = std::string{_name};
std::for_each(
_kind_name.begin(), _kind_name.end(), [](auto& v) { v = ::std::tolower(v); });
_category_count.emplace(_kind_name,
tool::execution_profile_category_data{itr.second, _unique_ops});
}
}
ar(cereal::make_nvp("threads", data.threads.size()));
ar(cereal::make_nvp("contexts", data.contexts.size()));
for(auto itr : _category_count)
ar(cereal::make_nvp(itr.first.c_str(), itr.second));
}
} // namespace cereal
+478 -262
View File
@@ -20,10 +20,13 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include "rocprofiler-sdk/defines.h"
#include "rocprofiler-sdk/dispatch_counting_service.h"
#define _GNU_SOURCE 1
#define _DEFAULT_SOURCE 1
#include "config.hpp"
#include "execution_profile.hpp"
#include "helper.hpp"
#include "stream_stack.hpp"
@@ -50,6 +53,7 @@
#include "lib/output/output_stream.hpp"
#include "lib/output/statistics.hpp"
#include "lib/output/stream_info.hpp"
#include "lib/output/timestamps.hpp"
#include "lib/output/tmp_file.hpp"
#include "lib/output/tmp_file_buffer.hpp"
@@ -63,11 +67,13 @@
#include <rocprofiler-sdk/internal_threading.h>
#include <rocprofiler-sdk/marker/api_id.h>
#include <rocprofiler-sdk/rocprofiler.h>
#include <rocprofiler-sdk/version.h>
#include <rocprofiler-sdk/cxx/hash.hpp>
#include <rocprofiler-sdk/cxx/operators.hpp>
#include <fmt/core.h>
#include <time.h>
#include <unistd.h>
#include <algorithm>
#include <cassert>
@@ -146,14 +152,6 @@ add_destructor(Tp*& ptr)
return ptr;
}
#define ADD_DESTRUCTOR(PTR) \
{ \
static auto _once = std::once_flag{}; \
std::call_once(_once, []() { add_destructor(PTR); }); \
}
#undef ADD_DESTRUCTOR
struct chained_siginfo
{
int signo = 0;
@@ -207,6 +205,11 @@ struct buffer_ids
rocjpeg_api_trace,
pc_sampling_stochastic};
}
auto pc_sampling_buffers_as_array() const
{
return std::array<rocprofiler_buffer_id_t, 2>{pc_sampling_host_trap,
pc_sampling_stochastic};
}
};
buffer_ids&
@@ -246,10 +249,11 @@ using kernel_iteration_t = std::unordered_map<rocprofiler_kernel_id_t, size_t
using kernel_rename_map_t = std::unordered_map<uint64_t, uint64_t>;
using kernel_rename_stack_t = std::stack<uint64_t>;
auto* tool_metadata = as_pointer<tool::metadata>(tool::metadata::inprocess{});
auto target_kernels = common::Synchronized<targeted_kernels_map_t>{};
std::mutex att_shader_data;
auto* tool_metadata = as_pointer<tool::metadata>(tool::metadata::inprocess{});
auto target_kernels = common::Synchronized<targeted_kernels_map_t>{};
auto* execution_profile = as_pointer<common::Synchronized<tool::execution_profile_data>>();
auto counter_collection_ctx = rocprofiler_context_id_t{0};
std::mutex att_shader_data;
thread_local auto thread_dispatch_rename = as_pointer<kernel_rename_stack_t>();
thread_local auto thread_dispatch_rename_dtor = common::scope_destructor{[]() {
@@ -336,10 +340,12 @@ get_client_ctx()
void
flush()
{
constexpr auto null_buffer_id = rocprofiler_buffer_id_t{.handle = 0};
ROCP_INFO << "flushing buffers...";
for(auto itr : get_buffers().as_array())
{
if(itr.handle > 0)
if(itr > null_buffer_id)
{
ROCP_INFO << "flushing buffer " << itr.handle;
ROCPROFILER_CALL(rocprofiler_flush_buffer(itr), "buffer flush");
@@ -419,6 +425,32 @@ collection_period_cntrl(std::promise<void>&& _promise, rocprofiler_context_id_t
}
}
int
record_execution_profile(rocprofiler_thread_id_t thr_id,
rocprofiler_context_id_t ctx_id,
rocprofiler_external_correlation_id_request_kind_t kind,
rocprofiler_tracing_operation_t op,
uint64_t /*internal_corr_id*/,
rocprofiler_user_data_t* /*external_corr_id*/,
void* /*user_data*/)
{
auto _record_data = [](tool::execution_profile_data& _data,
rocprofiler_thread_id_t _thr_id,
rocprofiler_context_id_t _ctx_id,
rocprofiler_external_correlation_id_request_kind_t _kind,
rocprofiler_tracing_operation_t _op) {
_data.category_count[_kind] += 1;
_data.category_op_count[_kind].emplace(_op);
_data.threads.emplace(_thr_id);
_data.contexts.emplace(_ctx_id);
};
if(execution_profile)
execution_profile->wlock(std::move(_record_data), thr_id, ctx_id, kind, op);
return 0;
}
int
set_kernel_rename_and_stream_display_correlation_id(
rocprofiler_thread_id_t thr_id,
@@ -623,6 +655,27 @@ runtime_initialization_callback(rocprofiler_callback_tracing_record_t record,
common::consume_args(user_data, data);
}
void
dummy_callback_tracing_callback(rocprofiler_callback_tracing_record_t /*record*/,
rocprofiler_user_data_t* /*user_data*/,
void* /*data*/)
{}
void
dummy_counter_dispatch_callback(rocprofiler_dispatch_counting_service_data_t,
rocprofiler_profile_config_id_t*,
rocprofiler_user_data_t*,
void*)
{}
void
dummy_counter_record_callback(rocprofiler_dispatch_counting_service_data_t,
rocprofiler_record_counter_t*,
size_t,
rocprofiler_user_data_t,
void*)
{}
void
callback_tracing_callback(rocprofiler_callback_tracing_record_t record,
rocprofiler_user_data_t* user_data,
@@ -865,6 +918,10 @@ code_object_tracing_callback(rocprofiler_callback_tracing_record_t record,
auto* sym_data = static_cast<tool::rocprofiler_kernel_symbol_info_t*>(record.payload);
if(record.phase == ROCPROFILER_CALLBACK_PHASE_LOAD)
{
ROCP_TRACE << fmt::format("adding kernel symbol info for kernel_id={} :: {}",
sym_data->kernel_id,
sym_data->kernel_name);
auto success = CHECK_NOTNULL(tool_metadata)
->add_kernel_symbol(kernel_symbol_info{
get_dereference(sym_data),
@@ -917,6 +974,15 @@ code_object_tracing_callback(rocprofiler_callback_tracing_record_t record,
(void) data;
}
void
dummy_buffered_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*/)
{}
void
buffered_tracing_callback(rocprofiler_context_id_t /*context*/,
rocprofiler_buffer_id_t /*buffer_id*/,
@@ -1234,12 +1300,12 @@ get_att_perfcounter_params(rocprofiler_agent_id_t agen
}
void
rocprofiler_pc_sampling_callback(rocprofiler_context_id_t /* context_id*/,
rocprofiler_buffer_id_t /* buffer_id*/,
rocprofiler_record_header_t** headers,
size_t num_headers,
void* /*data*/,
uint64_t /* drop_count*/)
pc_sampling_callback(rocprofiler_context_id_t /* context_id*/,
rocprofiler_buffer_id_t /* buffer_id*/,
rocprofiler_record_header_t** headers,
size_t num_headers,
void* /*data*/,
uint64_t /* drop_count*/)
{
if(!headers) return;
@@ -1345,10 +1411,10 @@ att_dispatch_callback(rocprofiler_agent_id_t /* agent_id */,
}
void
dispatch_callback(rocprofiler_dispatch_counting_service_data_t dispatch_data,
rocprofiler_counter_config_id_t* config,
rocprofiler_user_data_t* user_data,
void* /*callback_data_args*/)
counter_dispatch_callback(rocprofiler_dispatch_counting_service_data_t dispatch_data,
rocprofiler_counter_config_id_t* config,
rocprofiler_user_data_t* user_data,
void* /*callback_data_args*/)
{
static auto kernel_iteration = common::Synchronized<kernel_iteration_t, true>{};
@@ -1499,9 +1565,10 @@ if_pc_sample_config_match(rocprofiler_agent_id_t agent_id,
}
void
configure_pc_sampling_on_all_agents(uint64_t buffer_size,
uint64_t buffer_watermark,
void* tool_data)
configure_pc_sampling_on_all_agents(uint64_t buffer_size,
uint64_t buffer_watermark,
void* tool_data,
rocprofiler_buffer_tracing_cb_t pc_sampling_cb)
{
auto method = tool::get_config().pc_sampling_method_value;
auto unit = tool::get_config().pc_sampling_unit_value;
@@ -1515,7 +1582,7 @@ configure_pc_sampling_on_all_agents(uint64_t buffer_size,
buffer_size,
buffer_watermark,
ROCPROFILER_BUFFER_POLICY_LOSSLESS,
rocprofiler_pc_sampling_callback,
pc_sampling_cb,
tool_data,
buffer_id),
"buffer creation");
@@ -1544,9 +1611,81 @@ configure_pc_sampling_on_all_agents(uint64_t buffer_size,
ROCP_FATAL << "Given PC sampling configuration is not supported on any of the agents";
}
struct real_callbacks_t
{};
struct dummy_callbacks_t
{};
constexpr auto use_real_callbacks = real_callbacks_t{};
constexpr auto use_dummy_callbacks = dummy_callbacks_t{};
struct tracing_callbacks_t
{
tracing_callbacks_t() = delete;
tracing_callbacks_t(real_callbacks_t)
: code_object_tracing{code_object_tracing_callback}
, cntrl_tracing{cntrl_tracing_callback}
, kernel_rename{kernel_rename_callback}
, hip_stream{hip_stream_display_callback}
, callback_tracing{callback_tracing_callback}
, buffered_tracing{buffered_tracing_callback}
, pc_sampling{pc_sampling_callback}
, att_dispatch{att_dispatch_callback}
, att_shader_data{att_shader_data_callback}
, counter_dispatch{counter_dispatch_callback}
, counter_record{counter_record_callback}
{}
explicit tracing_callbacks_t(dummy_callbacks_t)
: code_object_tracing{dummy_callback_tracing_callback}
, cntrl_tracing{dummy_callback_tracing_callback}
, kernel_rename{dummy_callback_tracing_callback}
, hip_stream{dummy_callback_tracing_callback}
, callback_tracing{dummy_callback_tracing_callback}
, buffered_tracing{dummy_buffered_tracing_callback}
, pc_sampling{dummy_buffered_tracing_callback}
, counter_dispatch{dummy_counter_dispatch_callback}
, counter_record{dummy_counter_record_callback}
{}
const rocprofiler_callback_tracing_cb_t code_object_tracing = nullptr;
const rocprofiler_callback_tracing_cb_t cntrl_tracing = nullptr;
const rocprofiler_callback_tracing_cb_t kernel_rename = nullptr;
const rocprofiler_callback_tracing_cb_t hip_stream = nullptr;
const rocprofiler_callback_tracing_cb_t callback_tracing = nullptr;
const rocprofiler_buffer_tracing_cb_t buffered_tracing = nullptr;
const rocprofiler_buffer_tracing_cb_t pc_sampling = nullptr;
const rocprofiler_att_dispatch_callback_t att_dispatch = nullptr;
const rocprofiler_att_shader_data_callback_t att_shader_data = nullptr;
const rocprofiler_dispatch_counting_service_cb_t counter_dispatch = nullptr;
const rocprofiler_dispatch_counting_record_cb_t counter_record = nullptr;
};
auto
get_tracing_callbacks()
{
// for the benchmarking modes of sdk buffer/callback overhead, we are measuring the cost
// of the SDK invoking the callbacks to the tool. We do not want to include the overhead
// of the tool doing any work so we use "dummy" callbacks (i.e. functions which just
// immediately return)
if(tool::get_config().benchmark_mode == tool::config::benchmark::sdk_buffered_overhead ||
tool::get_config().benchmark_mode == tool::config::benchmark::sdk_callback_overhead ||
tool::get_config().benchmark_mode == tool::config::benchmark::execution_profile)
{
return tracing_callbacks_t{use_dummy_callbacks};
}
return tracing_callbacks_t{use_real_callbacks};
}
int
tool_init(rocprofiler_client_finalize_t fini_func, void* tool_data)
{
static constexpr auto null_context_id = rocprofiler_context_id_t{.handle = 0};
static constexpr auto null_buffer_id = rocprofiler_buffer_id_t{.handle = 0};
client_finalizer = fini_func;
const uint64_t buffer_size = 16 * common::units::get_page_size();
@@ -1556,18 +1695,39 @@ tool_init(rocprofiler_client_finalize_t fini_func, void* tool_data)
ROCPROFILER_CALL(rocprofiler_create_context(&get_client_ctx()), "create context failed");
auto code_obj_ctx = rocprofiler_context_id_t{0};
auto code_obj_ctx = null_context_id;
ROCPROFILER_CALL(rocprofiler_create_context(&code_obj_ctx), "failed to create context");
auto start_context = [](rocprofiler_context_id_t ctx_id, std::string_view msg) {
using benchmark = tool::config::benchmark;
// do not start context if we are benchmarking the overhead of a service
// being available but unused by any contexts
if(tool::get_config().benchmark_mode != benchmark::disabled_contexts_overhead &&
ctx_id != null_context_id)
{
if(tool::get_config().benchmark_mode == benchmark::execution_profile)
{
ROCPROFILER_CHECK(rocprofiler_configure_external_correlation_id_request_service(
ctx_id, nullptr, 0, record_execution_profile, nullptr));
}
ROCP_INFO << fmt::format("starting {} context...", msg);
ROCPROFILER_CHECK(rocprofiler_start_context(ctx_id));
}
};
auto callbacks = get_tracing_callbacks();
ROCPROFILER_CALL(
rocprofiler_configure_callback_tracing_service(code_obj_ctx,
ROCPROFILER_CALLBACK_TRACING_CODE_OBJECT,
nullptr,
0,
code_object_tracing_callback,
callbacks.code_object_tracing,
nullptr),
"code object tracing configure failed");
ROCPROFILER_CALL(rocprofiler_start_context(code_obj_ctx), "start context failed");
start_context(code_obj_ctx, "code object");
if(tool::get_config().marker_api_trace)
{
@@ -1576,11 +1736,11 @@ tool_init(rocprofiler_client_finalize_t fini_func, void* tool_data)
ROCPROFILER_CALLBACK_TRACING_MARKER_CORE_API,
nullptr,
0,
callback_tracing_callback,
callbacks.callback_tracing,
nullptr),
"callback tracing service failed to configure");
auto pause_resume_ctx = rocprofiler_context_id_t{0};
auto pause_resume_ctx = null_context_id;
ROCPROFILER_CALL(rocprofiler_create_context(&pause_resume_ctx), "failed to create context");
ROCPROFILER_CALL(rocprofiler_configure_callback_tracing_service(
@@ -1588,122 +1748,154 @@ tool_init(rocprofiler_client_finalize_t fini_func, void* tool_data)
ROCPROFILER_CALLBACK_TRACING_MARKER_CONTROL_API,
nullptr,
0,
cntrl_tracing_callback,
callbacks.cntrl_tracing,
static_cast<void*>(&get_client_ctx())),
"callback tracing service failed to configure");
ROCPROFILER_CALL(rocprofiler_start_context(pause_resume_ctx), "start context failed");
start_context(pause_resume_ctx, "marker pause/resume");
}
if(tool::get_config().kernel_trace)
struct buffer_service_config
{
ROCPROFILER_CALL(rocprofiler_create_buffer(get_client_ctx(),
buffer_size,
buffer_watermark,
ROCPROFILER_BUFFER_POLICY_LOSSLESS,
buffered_tracing_callback,
tool_data,
&get_buffers().kernel_trace),
"buffer creation");
bool option = false;
rocprofiler_buffer_tracing_kind_t kind = ROCPROFILER_BUFFER_TRACING_NONE;
rocprofiler_buffer_id_t& buffer_id;
};
ROCPROFILER_CALL(
rocprofiler_configure_buffer_tracing_service(get_client_ctx(),
ROCPROFILER_BUFFER_TRACING_KERNEL_DISPATCH,
nullptr,
0,
get_buffers().kernel_trace),
"buffer tracing service for kernel dispatch configure");
}
if(tool::get_config().memory_copy_trace)
for(auto&& itr : {buffer_service_config{tool::get_config().kernel_trace,
ROCPROFILER_BUFFER_TRACING_KERNEL_DISPATCH,
get_buffers().kernel_trace},
buffer_service_config{tool::get_config().memory_copy_trace,
ROCPROFILER_BUFFER_TRACING_MEMORY_COPY,
get_buffers().memory_copy_trace},
buffer_service_config{tool::get_config().scratch_memory_trace,
ROCPROFILER_BUFFER_TRACING_SCRATCH_MEMORY,
get_buffers().scratch_memory},
buffer_service_config{tool::get_config().hsa_core_api_trace,
ROCPROFILER_BUFFER_TRACING_HSA_CORE_API,
get_buffers().hsa_api_trace},
buffer_service_config{tool::get_config().hsa_amd_ext_api_trace,
ROCPROFILER_BUFFER_TRACING_HSA_AMD_EXT_API,
get_buffers().hsa_api_trace},
buffer_service_config{tool::get_config().hsa_image_ext_api_trace,
ROCPROFILER_BUFFER_TRACING_HSA_IMAGE_EXT_API,
get_buffers().hsa_api_trace},
buffer_service_config{tool::get_config().hsa_finalizer_ext_api_trace,
ROCPROFILER_BUFFER_TRACING_HSA_FINALIZE_EXT_API,
get_buffers().hsa_api_trace},
buffer_service_config{tool::get_config().hip_runtime_api_trace,
ROCPROFILER_BUFFER_TRACING_HIP_RUNTIME_API_EXT,
get_buffers().hip_api_trace},
buffer_service_config{tool::get_config().hip_compiler_api_trace,
ROCPROFILER_BUFFER_TRACING_HIP_COMPILER_API_EXT,
get_buffers().hip_api_trace},
buffer_service_config{tool::get_config().rccl_api_trace,
ROCPROFILER_BUFFER_TRACING_RCCL_API,
get_buffers().rccl_api_trace},
buffer_service_config{tool::get_config().memory_allocation_trace,
ROCPROFILER_BUFFER_TRACING_MEMORY_ALLOCATION,
get_buffers().memory_allocation_trace},
buffer_service_config{tool::get_config().rocdecode_api_trace,
ROCPROFILER_BUFFER_TRACING_ROCDECODE_API_EXT,
get_buffers().rocdecode_api_trace},
buffer_service_config{tool::get_config().rocjpeg_api_trace,
ROCPROFILER_BUFFER_TRACING_ROCJPEG_API,
get_buffers().rocjpeg_api_trace}})
{
ROCPROFILER_CALL(rocprofiler_create_buffer(get_client_ctx(),
buffer_size,
buffer_watermark,
ROCPROFILER_BUFFER_POLICY_LOSSLESS,
buffered_tracing_callback,
nullptr,
&get_buffers().memory_copy_trace),
"create memory copy buffer");
ROCPROFILER_CALL(
rocprofiler_configure_buffer_tracing_service(get_client_ctx(),
ROCPROFILER_BUFFER_TRACING_MEMORY_COPY,
nullptr,
0,
get_buffers().memory_copy_trace),
"buffer tracing service for memory copy configure");
}
if(tool::get_config().memory_allocation_trace)
{
ROCPROFILER_CALL(rocprofiler_create_buffer(get_client_ctx(),
buffer_size,
buffer_watermark,
ROCPROFILER_BUFFER_POLICY_LOSSLESS,
buffered_tracing_callback,
nullptr,
&get_buffers().memory_allocation_trace),
"create memory allocation buffer");
ROCPROFILER_CALL(rocprofiler_configure_buffer_tracing_service(
get_client_ctx(),
ROCPROFILER_BUFFER_TRACING_MEMORY_ALLOCATION,
nullptr,
0,
get_buffers().memory_allocation_trace),
"buffer tracing service for memory allocation configure");
}
if(tool::get_config().scratch_memory_trace)
{
ROCPROFILER_CALL(rocprofiler_create_buffer(get_client_ctx(),
buffer_size,
buffer_watermark,
ROCPROFILER_BUFFER_POLICY_LOSSLESS,
buffered_tracing_callback,
tool_data,
&get_buffers().scratch_memory),
"buffer creation");
ROCPROFILER_CALL(
rocprofiler_configure_buffer_tracing_service(get_client_ctx(),
ROCPROFILER_BUFFER_TRACING_SCRATCH_MEMORY,
nullptr,
0,
get_buffers().scratch_memory),
"buffer tracing service for scratch memory configure");
}
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,
buffer_watermark,
ROCPROFILER_BUFFER_POLICY_LOSSLESS,
buffered_tracing_callback,
tool_data,
&get_buffers().hsa_api_trace),
"buffer creation");
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_amd_ext_api_trace,
ROCPROFILER_BUFFER_TRACING_HSA_AMD_EXT_API},
optpair_t{tool::get_config().hsa_image_ext_api_trace,
ROCPROFILER_BUFFER_TRACING_HSA_IMAGE_EXT_API},
optpair_t{tool::get_config().hsa_finalizer_ext_api_trace,
ROCPROFILER_BUFFER_TRACING_HSA_FINALIZE_EXT_API}})
if(itr.option)
{
if(itr.first)
// in sdk callback overhead benchmarking, we don't want to use the buffer services
if(tool::get_config().benchmark_mode == tool::config::benchmark::sdk_callback_overhead)
continue;
if(itr.buffer_id == null_buffer_id)
{
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");
ROCPROFILER_CALL(rocprofiler_create_buffer(get_client_ctx(),
buffer_size,
buffer_watermark,
ROCPROFILER_BUFFER_POLICY_LOSSLESS,
callbacks.buffered_tracing,
tool_data,
&itr.buffer_id),
"buffer creation");
ROCP_FATAL_IF(itr.buffer_id.handle == 0) << "failed to create buffer";
auto cb_thread = rocprofiler_callback_thread_t{};
ROCP_INFO << "creating dedicated callback thread for buffer "
<< itr.buffer_id.handle;
ROCPROFILER_CALL(rocprofiler_create_callback_thread(&cb_thread),
"creating callback thread");
ROCP_INFO << "assigning buffer " << itr.buffer_id.handle << " to callback thread "
<< cb_thread.handle;
ROCPROFILER_CALL(rocprofiler_assign_callback_thread(itr.buffer_id, cb_thread),
"assigning callback thread");
}
ROCPROFILER_CALL(rocprofiler_configure_buffer_tracing_service(
get_client_ctx(), itr.kind, nullptr, 0, itr.buffer_id),
"buffer tracing service configure");
}
}
struct callback_service_config
{
bool option = false;
rocprofiler_callback_tracing_kind_t kind = ROCPROFILER_CALLBACK_TRACING_NONE;
rocprofiler_callback_tracing_cb_t callback = nullptr;
};
for(auto&& itr : {callback_service_config{tool::get_config().kernel_trace,
ROCPROFILER_CALLBACK_TRACING_KERNEL_DISPATCH,
dummy_callback_tracing_callback},
callback_service_config{tool::get_config().memory_copy_trace,
ROCPROFILER_CALLBACK_TRACING_MEMORY_COPY,
dummy_callback_tracing_callback},
callback_service_config{tool::get_config().scratch_memory_trace,
ROCPROFILER_CALLBACK_TRACING_SCRATCH_MEMORY,
dummy_callback_tracing_callback},
callback_service_config{tool::get_config().hsa_core_api_trace,
ROCPROFILER_CALLBACK_TRACING_HSA_CORE_API,
dummy_callback_tracing_callback},
callback_service_config{tool::get_config().hsa_amd_ext_api_trace,
ROCPROFILER_CALLBACK_TRACING_HSA_AMD_EXT_API,
dummy_callback_tracing_callback},
callback_service_config{tool::get_config().hsa_image_ext_api_trace,
ROCPROFILER_CALLBACK_TRACING_HSA_IMAGE_EXT_API,
dummy_callback_tracing_callback},
callback_service_config{tool::get_config().hsa_finalizer_ext_api_trace,
ROCPROFILER_CALLBACK_TRACING_HSA_FINALIZE_EXT_API,
dummy_callback_tracing_callback},
callback_service_config{tool::get_config().hip_runtime_api_trace,
ROCPROFILER_CALLBACK_TRACING_HIP_RUNTIME_API,
dummy_callback_tracing_callback},
callback_service_config{tool::get_config().hip_compiler_api_trace,
ROCPROFILER_CALLBACK_TRACING_HIP_COMPILER_API,
dummy_callback_tracing_callback},
callback_service_config{tool::get_config().rccl_api_trace,
ROCPROFILER_CALLBACK_TRACING_RCCL_API,
dummy_callback_tracing_callback},
callback_service_config{tool::get_config().memory_allocation_trace,
ROCPROFILER_CALLBACK_TRACING_MEMORY_ALLOCATION,
dummy_callback_tracing_callback},
callback_service_config{tool::get_config().rocdecode_api_trace,
ROCPROFILER_CALLBACK_TRACING_ROCDECODE_API,
dummy_callback_tracing_callback},
callback_service_config{tool::get_config().rocjpeg_api_trace,
ROCPROFILER_CALLBACK_TRACING_ROCJPEG_API,
dummy_callback_tracing_callback}})
{
if(itr.option)
{
// in sdk callback overhead benchmarking, we don't want to use the buffer services
if(tool::get_config().benchmark_mode != tool::config::benchmark::sdk_callback_overhead)
continue;
ROCPROFILER_CALL(rocprofiler_configure_callback_tracing_service(
get_client_ctx(), itr.kind, nullptr, 0, itr.callback, nullptr),
"callback tracing service failed to configure");
}
}
@@ -1748,120 +1940,28 @@ tool_init(rocprofiler_client_finalize_t fini_func, void* tool_data)
id,
agent_params.data(),
agent_params.size(),
att_dispatch_callback,
att_shader_data_callback,
callbacks.att_dispatch,
callbacks.att_shader_data,
tool_data),
"thread trace service configure");
}
}
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,
buffer_watermark,
ROCPROFILER_BUFFER_POLICY_LOSSLESS,
buffered_tracing_callback,
tool_data,
&get_buffers().hip_api_trace),
"buffer creation");
if(tool::get_config().hip_runtime_api_trace)
{
ROCPROFILER_CALL(rocprofiler_configure_buffer_tracing_service(
get_client_ctx(),
ROCPROFILER_BUFFER_TRACING_HIP_RUNTIME_API_EXT,
nullptr,
0,
get_buffers().hip_api_trace),
"buffer tracing service for hip api configure");
}
if(tool::get_config().hip_compiler_api_trace)
{
ROCPROFILER_CALL(rocprofiler_configure_buffer_tracing_service(
get_client_ctx(),
ROCPROFILER_BUFFER_TRACING_HIP_COMPILER_API_EXT,
nullptr,
0,
get_buffers().hip_api_trace),
"buffer tracing service for hip compiler api configure");
}
}
if(tool::get_config().rccl_api_trace)
{
ROCPROFILER_CALL(rocprofiler_create_buffer(get_client_ctx(),
buffer_size,
buffer_watermark,
ROCPROFILER_BUFFER_POLICY_LOSSLESS,
buffered_tracing_callback,
tool_data,
&get_buffers().rccl_api_trace),
"buffer creation");
ROCPROFILER_CALL(
rocprofiler_configure_buffer_tracing_service(get_client_ctx(),
ROCPROFILER_BUFFER_TRACING_RCCL_API,
nullptr,
0,
get_buffers().rccl_api_trace),
"buffer tracing service for rccl api configure");
}
if(tool::get_config().counter_collection)
{
ROCPROFILER_CALL(rocprofiler_create_context(&counter_collection_ctx),
"failed to create context");
"failed to create counter collection context");
ROCPROFILER_CALL(
rocprofiler_configure_callback_dispatch_counting_service(counter_collection_ctx,
dispatch_callback,
callbacks.counter_dispatch,
nullptr,
counter_record_callback,
callbacks.counter_record,
nullptr),
"Could not setup counting service");
ROCPROFILER_CALL(rocprofiler_start_context(counter_collection_ctx), "start context failed");
start_context(counter_collection_ctx, "counter collection");
}
if(tool::get_config().rocdecode_api_trace)
{
ROCPROFILER_CALL(rocprofiler_create_buffer(get_client_ctx(),
buffer_size,
buffer_watermark,
ROCPROFILER_BUFFER_POLICY_LOSSLESS,
buffered_tracing_callback,
tool_data,
&get_buffers().rocdecode_api_trace),
"buffer creation");
ROCPROFILER_CALL(rocprofiler_configure_buffer_tracing_service(
get_client_ctx(),
ROCPROFILER_BUFFER_TRACING_ROCDECODE_API_EXT,
nullptr,
0,
get_buffers().rocdecode_api_trace),
"buffer tracing service for ROCDecode api configure");
}
if(tool::get_config().rocjpeg_api_trace)
{
ROCPROFILER_CALL(rocprofiler_create_buffer(get_client_ctx(),
buffer_size,
buffer_watermark,
ROCPROFILER_BUFFER_POLICY_LOSSLESS,
buffered_tracing_callback,
tool_data,
&get_buffers().rocjpeg_api_trace),
"buffer creation");
ROCPROFILER_CALL(
rocprofiler_configure_buffer_tracing_service(get_client_ctx(),
ROCPROFILER_BUFFER_TRACING_ROCJPEG_API,
nullptr,
0,
get_buffers().rocjpeg_api_trace),
"buffer tracing service for ROCDecode api configure");
}
if(tool::get_config().kernel_rename)
{
auto rename_ctx = rocprofiler_context_id_t{0};
@@ -1877,34 +1977,38 @@ tool_init(rocprofiler_client_finalize_t fini_func, void* tool_data)
ROCPROFILER_CALLBACK_TRACING_MARKER_CORE_API,
marker_core_api_kinds.data(),
marker_core_api_kinds.size(),
kernel_rename_callback,
callbacks.kernel_rename,
nullptr),
"callback tracing service failed to configure");
ROCPROFILER_CALL(rocprofiler_start_context(rename_ctx), "start context failed");
start_context(rename_ctx, "kernel rename");
}
if(!tool::get_config().group_by_queue)
{
// Track stream ID information via callback service
auto hip_stream_display_ctx = rocprofiler_context_id_t{0};
ROCPROFILER_CALL(rocprofiler_create_context(&hip_stream_display_ctx),
"failed to create context");
"failed to create hip stream context");
ROCPROFILER_CALL(
rocprofiler_configure_callback_tracing_service(hip_stream_display_ctx,
ROCPROFILER_CALLBACK_TRACING_HIP_STREAM,
nullptr,
0,
hip_stream_display_callback,
callbacks.hip_stream,
nullptr),
"stream tracing configure failed");
ROCPROFILER_CALL(rocprofiler_start_context(hip_stream_display_ctx), "start context failed");
"hip stream tracing configure failed");
start_context(hip_stream_display_ctx, "hip stream");
// Track if HIP runtime has been initialized via runtime_intialization service
auto runtime_initialization_ctx = rocprofiler_context_id_t{0};
ROCPROFILER_CALL(rocprofiler_create_context(&runtime_initialization_ctx),
"failed to create context");
"failed to create runtime initialization context");
ROCPROFILER_CALL(rocprofiler_configure_callback_tracing_service(
runtime_initialization_ctx,
ROCPROFILER_CALLBACK_TRACING_RUNTIME_INITIALIZATION,
@@ -1912,11 +2016,13 @@ tool_init(rocprofiler_client_finalize_t fini_func, void* tool_data)
0,
runtime_initialization_callback,
nullptr),
"stream tracing configure failed");
ROCPROFILER_CALL(rocprofiler_start_context(runtime_initialization_ctx),
"start context failed");
"runtime initialization tracing configure failed");
start_context(runtime_initialization_ctx, "runtime initialization");
}
if(tool::get_config().kernel_rename || !tool::get_config().group_by_queue)
if((tool::get_config().kernel_rename || !tool::get_config().group_by_queue) &&
tool::get_config().benchmark_mode != tool::config::benchmark::execution_profile)
{
auto external_corr_id_request_kinds =
std::array<rocprofiler_external_correlation_id_request_kind_t, 2>{
@@ -1949,16 +2055,18 @@ tool_init(rocprofiler_client_finalize_t fini_func, void* tool_data)
if(tool::get_config().pc_sampling_host_trap)
{
configure_pc_sampling_on_all_agents(buffer_size, buffer_watermark, tool_data);
configure_pc_sampling_on_all_agents(
buffer_size, buffer_watermark, tool_data, callbacks.pc_sampling);
}
else if(tool::get_config().pc_sampling_stochastic)
{
configure_pc_sampling_on_all_agents(buffer_size, buffer_watermark, tool_data);
configure_pc_sampling_on_all_agents(
buffer_size, buffer_watermark, tool_data, callbacks.pc_sampling);
}
for(auto itr : get_buffers().as_array())
for(auto itr : get_buffers().pc_sampling_buffers_as_array())
{
if(itr.handle > 0)
if(itr > null_buffer_id)
{
auto cb_thread = rocprofiler_callback_thread_t{};
@@ -1973,24 +2081,38 @@ tool_init(rocprofiler_client_finalize_t fini_func, void* tool_data)
}
}
if(tool::get_config().collection_periods.empty())
{
ROCPROFILER_CHECK(rocprofiler_start_context(get_client_ctx()));
}
else
{
auto _prom = std::promise<void>{};
auto _fut = _prom.get_future();
std::thread{collection_period_cntrl, std::move(_prom), get_client_ctx()}.detach();
_fut.wait_for(std::chrono::seconds{1}); // wait for a max of 1 second
}
// Handle kernel id of zero
bool include = std::regex_search("0", std::regex(tool::get_config().kernel_filter_include));
bool exclude = std::regex_search("0", std::regex(tool::get_config().kernel_filter_exclude));
if(include && (!exclude || tool::get_config().kernel_filter_exclude.empty()))
add_kernel_target(0, tool::get_config().kernel_filter_range);
if(tool::get_config().benchmark_mode == tool::config::benchmark::disabled_contexts_overhead)
{
ROCP_INFO << "rocprofv3 is not recording data because the overhead of inactive contexts is "
"being benchmarked";
}
else if(tool::get_config().selected_regions)
{
ROCP_WARNING << "rocprofv3 is only recording profiling data within regions of code "
"surrounded by roctxProfilerResume(0)/roctxProfilerPause";
}
else if(!tool::get_config().collection_periods.empty())
{
ROCP_INFO << "rocprofv3 will record data during the defined collection period(s)";
auto _prom = std::promise<void>{};
auto _fut = _prom.get_future();
std::thread{collection_period_cntrl, std::move(_prom), get_client_ctx()}.detach();
_fut.wait_for(std::chrono::seconds{1}); // wait for a max of 1 second
}
else
{
ROCP_INFO << "rocprofv3 will record data starting now";
start_context(get_client_ctx(), "primary rocprofv3");
}
tool_metadata->process_id = getpid();
rocprofiler_get_timestamp(&(tool_metadata->process_start_ns));
@@ -2008,6 +2130,90 @@ struct output_data
uint64_t num_bytes = 0;
};
void
generate_config_output(const tool::config& cfg, const tool::metadata& tool_metadata_v)
{
using JSONOutputArchive = ::cereal::PrettyJSONOutputArchive;
constexpr auto json_prec = 16;
constexpr auto json_indent = JSONOutputArchive::Options::IndentChar::space;
auto json_opts = JSONOutputArchive::Options{json_prec, json_indent, 2};
auto filename = std::string_view{"config"};
auto stream = get_output_stream(cfg, filename, ".json");
{
auto archive = JSONOutputArchive{*stream.stream, json_opts};
archive.setNextName("rocprofiler-sdk-tool");
archive.startNode();
archive.makeArray();
archive.startNode(); // first array entry
auto timestamps =
tool::timestamps_t{tool_metadata_v.process_start_ns, tool_metadata_v.process_end_ns};
auto this_pid = tool_metadata_v.process_id;
archive.setNextName("metadata");
archive.startNode();
archive(cereal::make_nvp("pid", this_pid));
archive(cereal::make_nvp("init_time", timestamps.app_start_time));
archive(cereal::make_nvp("fini_time", timestamps.app_end_time));
archive(cereal::make_nvp("config", cfg));
archive(cereal::make_nvp("command", common::read_command_line(this_pid)));
{
archive.setNextName("build_spec");
archive.startNode();
archive(cereal::make_nvp("version_major", ROCPROFILER_VERSION_MAJOR));
archive(cereal::make_nvp("version_minor", ROCPROFILER_VERSION_MINOR));
archive(cereal::make_nvp("version_patch", ROCPROFILER_VERSION_PATCH));
archive(cereal::make_nvp("soversion", ROCPROFILER_SOVERSION));
archive(cereal::make_nvp("compiler_id", std::string{ROCPROFILER_COMPILER_ID}));
archive(
cereal::make_nvp("compiler_version", std::string{ROCPROFILER_COMPILER_VERSION}));
archive(cereal::make_nvp("git_describe", std::string{ROCPROFILER_GIT_DESCRIBE}));
archive(cereal::make_nvp("git_revision", std::string{ROCPROFILER_GIT_REVISION}));
archive(cereal::make_nvp("library_arch", std::string{ROCPROFILER_LIBRARY_ARCH}));
archive(cereal::make_nvp("system_name", std::string{ROCPROFILER_SYSTEM_NAME}));
archive(
cereal::make_nvp("system_processor", std::string{ROCPROFILER_SYSTEM_PROCESSOR}));
archive(cereal::make_nvp("system_version", std::string{ROCPROFILER_SYSTEM_VERSION}));
archive.finishNode(); // build_spec
}
// save the execution profile
if(execution_profile) archive(cereal::make_nvp("profile", execution_profile->get()));
// save the environment variables
{
archive.setNextName("environment");
archive.startNode();
size_t idx = 0;
while(true)
{
const auto* env_entry = environ[idx++];
if(!env_entry)
break;
else if(std::string_view{env_entry}.find('=') != std::string_view::npos)
{
auto _entry = std::string{env_entry};
auto _pos = _entry.find('=');
auto _name = _entry.substr(0, _pos);
auto _value = _entry.substr(_pos + 1);
archive(cereal::make_nvp(_name.c_str(), _value));
}
}
archive.finishNode();
}
archive.finishNode(); // metadata
archive.finishNode(); // first array entry
archive.finishNode(); // rocprofiler-sdk-tool
}
stream.close();
}
template <typename Tp, domain_type DomainT>
void
generate_output(tool::buffered_output<Tp, DomainT>& output_v,
@@ -2019,6 +2225,9 @@ generate_output(tool::buffered_output<Tp, DomainT>& output_v,
if(!output_v) return;
// when benchmarking, we do not generate output
if(tool::get_config().benchmark_mode != tool::config::benchmark::none) return;
// opens temporary file and sets read position to beginning
output_v.read();
@@ -2104,6 +2313,12 @@ tool_fini(void* /*tool_data*/)
cleanups.clear();
};
// generate the configuration output regardless of whether there is any data
if(tool::get_config().output_config_file)
{
generate_config_output(tool::get_config(), *tool_metadata);
}
auto _dtor = common::scope_destructor{run_cleanup};
generate_output(kernel_dispatch_output, outdata, contributions, cleanups);
@@ -2662,6 +2877,7 @@ rocprofiler_configure(uint32_t version,
// ensure these pointers are not leaked
add_destructor(tool_metadata);
add_destructor(execution_profile);
// in case main wrapper is not used
::atexit([]() { finalize_rocprofv3("atexit"); });
@@ -20,13 +20,13 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include <rocprofiler-sdk/external_correlation.h>
#include <rocprofiler-sdk/fwd.h>
#include "lib/rocprofiler-sdk/external_correlation.hpp"
#include "lib/common/synchronized.hpp"
#include "lib/common/utility.hpp"
#include "lib/rocprofiler-sdk/context/context.hpp"
#include "lib/rocprofiler-sdk/external_correlation.hpp"
#include <rocprofiler-sdk/external_correlation.h>
#include <rocprofiler-sdk/fwd.h>
#include <unistd.h>
@@ -36,6 +36,50 @@ namespace external_correlation
{
namespace
{
#define ROCPROFILER_EXTERNAL_CORRELATION_REQUEST_KIND_STRING(CODE) \
template <> \
struct external_correlation_id_request_kind_string< \
ROCPROFILER_EXTERNAL_CORRELATION_REQUEST_##CODE> \
{ \
static constexpr auto value = \
std::pair<const char*, size_t>{#CODE, std::string_view{#CODE}.length()}; \
};
template <size_t Idx>
struct external_correlation_id_request_kind_string;
ROCPROFILER_EXTERNAL_CORRELATION_REQUEST_KIND_STRING(NONE)
ROCPROFILER_EXTERNAL_CORRELATION_REQUEST_KIND_STRING(HSA_CORE_API)
ROCPROFILER_EXTERNAL_CORRELATION_REQUEST_KIND_STRING(HSA_AMD_EXT_API)
ROCPROFILER_EXTERNAL_CORRELATION_REQUEST_KIND_STRING(HSA_IMAGE_EXT_API)
ROCPROFILER_EXTERNAL_CORRELATION_REQUEST_KIND_STRING(HSA_FINALIZE_EXT_API)
ROCPROFILER_EXTERNAL_CORRELATION_REQUEST_KIND_STRING(HIP_RUNTIME_API)
ROCPROFILER_EXTERNAL_CORRELATION_REQUEST_KIND_STRING(HIP_COMPILER_API)
ROCPROFILER_EXTERNAL_CORRELATION_REQUEST_KIND_STRING(MARKER_CORE_API)
ROCPROFILER_EXTERNAL_CORRELATION_REQUEST_KIND_STRING(MARKER_CONTROL_API)
ROCPROFILER_EXTERNAL_CORRELATION_REQUEST_KIND_STRING(MARKER_NAME_API)
ROCPROFILER_EXTERNAL_CORRELATION_REQUEST_KIND_STRING(MEMORY_COPY)
ROCPROFILER_EXTERNAL_CORRELATION_REQUEST_KIND_STRING(MEMORY_ALLOCATION)
ROCPROFILER_EXTERNAL_CORRELATION_REQUEST_KIND_STRING(KERNEL_DISPATCH)
ROCPROFILER_EXTERNAL_CORRELATION_REQUEST_KIND_STRING(SCRATCH_MEMORY)
ROCPROFILER_EXTERNAL_CORRELATION_REQUEST_KIND_STRING(RCCL_API)
ROCPROFILER_EXTERNAL_CORRELATION_REQUEST_KIND_STRING(OMPT)
ROCPROFILER_EXTERNAL_CORRELATION_REQUEST_KIND_STRING(ROCDECODE_API)
ROCPROFILER_EXTERNAL_CORRELATION_REQUEST_KIND_STRING(ROCJPEG_API)
#undef ROCPROFILER_EXTERNAL_CORRELATION_REQUEST_KIND_STRING
template <size_t Idx, size_t... Tail>
std::pair<const char*, size_t>
get_kind_name(rocprofiler_external_correlation_id_request_kind_t kind,
std::index_sequence<Idx, Tail...>)
{
if(kind == Idx) return external_correlation_id_request_kind_string<Idx>::value;
// recursion until tail empty
if constexpr(sizeof...(Tail) > 0) return get_kind_name(kind, std::index_sequence<Tail...>{});
return {nullptr, 0};
}
auto
get_default_tid()
{
@@ -249,6 +293,21 @@ rocprofiler_configure_external_correlation_id_request_service(
callback, callback_args, kinds_v);
}
rocprofiler_status_t
rocprofiler_query_external_correlation_id_request_kind_name(
rocprofiler_external_correlation_id_request_kind_t kind,
const char** name,
uint64_t* name_len)
{
auto&& val = rocprofiler::external_correlation::get_kind_name(
kind, std::make_index_sequence<ROCPROFILER_EXTERNAL_CORRELATION_REQUEST_LAST>{});
if(name) *name = val.first;
if(name_len) *name_len = val.second;
return (val.first) ? ROCPROFILER_STATUS_SUCCESS : ROCPROFILER_STATUS_ERROR_KIND_NOT_FOUND;
}
rocprofiler_status_t
rocprofiler_push_external_correlation_id(rocprofiler_context_id_t context,
rocprofiler_thread_id_t tid,
@@ -42,6 +42,7 @@ namespace context
{
struct context;
}
namespace external_correlation
{
static constexpr bool enable_const_wlock_v = true;
@@ -688,6 +688,33 @@ initialize()
if(get_num_clients() > 0) internal_threading::initialize();
// initialization is no longer available
set_init_status(1);
if(get_num_clients() > 0)
{
for(const auto& itr : *get_clients())
{
if(!itr) continue;
size_t _client_registered_ctx = 0;
for(const auto* citr : context::get_registered_contexts())
{
if(citr->client_idx == itr->internal_client_id.handle) ++_client_registered_ctx;
}
size_t _client_activated_ctx = 0;
for(const auto* citr : context::get_active_contexts())
{
if(citr->client_idx == itr->internal_client_id.handle) ++_client_activated_ctx;
}
ROCP_INFO << fmt::format("rocprofiler-sdk client '{}' registered {} context(s) and "
"started {} context(s)",
(itr->mutable_client_id.name)
? std::string_view{itr->mutable_client_id.name}
: std::string_view{"unspecified"},
_client_registered_ctx,
_client_activated_ctx);
}
}
});
}