Put cached perfetto traces as default one (#2138)

* Put cached perfetto traces as default one

* Improve cached data and perfetto traces in order to be more aligned with E2E tests

* Addressing PR comments and findings

* Force early instrumentation bundle instantiation

* Sync-up insturumented containers with thread growth data

* Revert ompvv number of host threads to default 8

* Fixed counter track namings for amd-smi

* AIPROFSYST-34 [rocprof-sys] Update documentation describing newly introduced changes to default tracing mechanism
Este commit está contenido en:
marantic-amd
2025-12-22 12:47:35 +01:00
cometido por GitHub
padre 7da3275b42
commit ba1380a75d
Se han modificado 36 ficheros con 557 adiciones y 183 borrados
@@ -340,10 +340,11 @@ generate_config(std::string _config_file, const std::set<std::string>& _config_f
if(_romni && !_lomni) return false;
for(const auto* itr :
{ "ROCPROFSYS_CONFIG", "ROCPROFSYS_MODE", "ROCPROFSYS_TRACE_CACHED",
"ROCPROFSYS_TRACE", "ROCPROFSYS_PROFILE", "ROCPROFSYS_USE_SAMPLING",
"ROCPROFSYS_USE_PROCESS_SAMPLING", "ROCPROFSYS_USE_ROCM",
"ROCPROFSYS_USE_AMD_SMI", "ROCPROFSYS_USE_KOKKOSP",
"ROCPROFSYS_USE_OMPT", "ROCPROFSYS_USE", "ROCPROFSYS_OUTPUT" })
"ROCPROFSYS_TRACE_LEGACY", "ROCPROFSYS_PROFILE",
"ROCPROFSYS_USE_SAMPLING", "ROCPROFSYS_USE_PROCESS_SAMPLING",
"ROCPROFSYS_USE_ROCM", "ROCPROFSYS_USE_AMD_SMI",
"ROCPROFSYS_USE_KOKKOSP", "ROCPROFSYS_USE_OMPT", "ROCPROFSYS_USE",
"ROCPROFSYS_OUTPUT" })
{
if(_lhs->get_env_name().find(itr) == 0 &&
_rhs->get_env_name().find(itr) != 0)
@@ -189,7 +189,7 @@ get_initial_environment()
update_env(_env, "ROCPROFSYS_TRACE_CACHED", false);
update_env(_env, "ROCPROFSYS_PROFILE", false);
update_env(_env, "ROCPROFSYS_USE_PROCESS_SAMPLING", false);
update_env(_env, "ROCPROFSYS_TRACE", false);
update_env(_env, "ROCPROFSYS_TRACE_LEGACY", false);
update_env(_env, "ROCPROFSYS_THREAD_POOL_SIZE",
get_env<int>("ROCPROFSYS_THREAD_POOL_SIZE", 0));
update_env(_env, "ROCPROFSYS_LAUNCHER", "rocprof-sys-causal");
@@ -339,20 +339,23 @@ parse_args(int argc, char** argv, std::vector<char*>& _env)
original_envs);
});
parser
.add_argument({ "-T", "--trace" }, "Generate a detailed trace (perfetto output)")
.add_argument(
{ "-T", "--trace" },
"Generate a detailed trace with deferred trace generation (perfetto output)")
.max_count(1)
.action([&](parser_t& p) {
rocprofsys::common::update_env(_env, "ROCPROFSYS_TRACE", p.get<bool>("trace"),
update_mode::REPLACE, ":", updated_envs,
original_envs);
rocprofsys::common::update_env(_env, "ROCPROFSYS_TRACE_CACHED",
p.get<bool>("trace"), update_mode::REPLACE,
":", updated_envs, original_envs);
});
parser
.add_argument({ "--trace-cached" },
"Generate a detailed trace (perfetto output) from cached data ")
.add_argument(
{ "-L", "--trace-legacy" },
"Generate a detailed trace with direct mode (perfetto output, legacy)")
.max_count(1)
.action([&](parser_t& p) {
rocprofsys::common::update_env(
_env, "ROCPROFSYS_TRACE_CACHED", p.get<bool>("trace-cached"),
_env, "ROCPROFSYS_TRACE_LEGACY", p.get<bool>("trace-legacy"),
update_mode::REPLACE, ":", updated_envs, original_envs);
});
parser
@@ -301,14 +301,24 @@ add_core_arguments(parser_t& _parser, parser_data& _data)
if(_data.environ_filter("trace", _data))
{
_parser
.add_argument({ "-T", "--trace" },
"Generate a detailed trace (perfetto output)")
.add_argument({ "-T", "--trace" }, "Generate a detailed trace with deferred "
"trace generation (perfetto output)")
.max_count(1)
.action([&](parser_t& p) {
update_env(_data, "ROCPROFSYS_TRACE", p.get<bool>("trace"));
update_env(_data, "ROCPROFSYS_TRACE_CACHED", p.get<bool>("trace"));
});
_parser
.add_argument(
{ "-L", "--trace-legacy" },
"Generate a detailed trace with direct mode (perfetto output, legacy)")
.max_count(1)
.action([&](parser_t& p) {
update_env(_data, "ROCPROFSYS_TRACE_LEGACY", p.get<bool>("trace-legacy"));
});
_data.processed_environs.emplace("trace");
_data.processed_environs.emplace("trace_legacy");
}
if(_data.environ_filter("profile", _data))
@@ -299,20 +299,32 @@ configure_settings(bool _init)
get_env<size_t>("ROCPROFSYS_NUM_THREADS", 1), "threading", "performance",
"sampling", "parallelism", "advanced");
ROCPROFSYS_CONFIG_SETTING(bool, "ROCPROFSYS_TRACE", "Enable perfetto backend",
_default_perfetto_v, "backend", "perfetto");
ROCPROFSYS_CONFIG_SETTING(bool, "ROCPROFSYS_TRACE_CACHED",
"Enable perfetto backend with deferred trace generation "
"for minimal runtime overhead",
_default_perfetto_v, "backend", "perfetto_caching");
ROCPROFSYS_CONFIG_SETTING(bool, "ROCPROFSYS_TRACE_LEGACY",
"Enable perfetto backend (legacy, direct mode)", false,
"backend", "perfetto");
ROCPROFSYS_CONFIG_SETTING(bool, "ROCPROFSYS_TRACE",
"[DEPRECATED] Renamed to ROCPROFSYS_TRACE_LEGACY", false,
"backend", "perfetto", "deprecated");
ROCPROFSYS_CONFIG_SETTING(bool, "ROCPROFSYS_USE_PERFETTO",
"[DEPRECATED] Renamed to ROCPROFSYS_TRACE",
_default_perfetto_v, "backend", "perfetto", "deprecated");
"[DEPRECATED] Renamed to ROCPROFSYS_TRACE_LEGACY", false,
"backend", "perfetto", "deprecated");
ROCPROFSYS_CONFIG_SETTING(bool, "ROCPROFSYS_PROFILE", "Enable timemory backend",
!_config->get<bool>("ROCPROFSYS_TRACE"), "backend",
"timemory");
!(_config->get<bool>("ROCPROFSYS_TRACE_LEGACY") ||
_config->get<bool>("ROCPROFSYS_TRACE_CACHED")),
"backend", "timemory");
ROCPROFSYS_CONFIG_SETTING(
bool, "ROCPROFSYS_USE_TIMEMORY", "[DEPRECATED] Renamed to ROCPROFSYS_PROFILE",
!_config->get<bool>("ROCPROFSYS_TRACE"), "backend", "timemory", "deprecated");
ROCPROFSYS_CONFIG_SETTING(bool, "ROCPROFSYS_USE_TIMEMORY",
"[DEPRECATED] Renamed to ROCPROFSYS_PROFILE",
!_config->get<bool>("ROCPROFSYS_TRACE_LEGACY"), "backend",
"timemory", "deprecated");
ROCPROFSYS_CONFIG_SETTING(bool, "ROCPROFSYS_USE_CAUSAL",
"Enable causal profiling analysis", false, "backend",
@@ -321,10 +333,6 @@ configure_settings(bool _init)
ROCPROFSYS_CONFIG_SETTING(bool, "ROCPROFSYS_USE_ROCPD", "Enable rocpd backend", false,
"backend", "rocpd");
ROCPROFSYS_CONFIG_SETTING(bool, "ROCPROFSYS_TRACE_CACHED",
"Enable perfetto with trace cache", false, "backend",
"perfetto_caching");
ROCPROFSYS_CONFIG_SETTING(bool, "ROCPROFSYS_USE_ROCM",
"Enable ROCm API and kernel tracing", true, "backend",
"rocm");
@@ -1060,7 +1068,8 @@ configure_settings(bool _init)
handle_deprecated_setting("ROCPROFSYS_USE_THREAD_SAMPLING",
"ROCPROFSYS_USE_PROCESS_SAMPLING");
handle_deprecated_setting("ROCPROFSYS_OUTPUT_FILE", "ROCPROFSYS_PERFETTO_FILE");
handle_deprecated_setting("ROCPROFSYS_USE_PERFETTO", "ROCPROFSYS_TRACE");
handle_deprecated_setting("ROCPROFSYS_USE_PERFETTO", "ROCPROFSYS_TRACE_LEGACY");
handle_deprecated_setting("ROCPROFSYS_TRACE", "ROCPROFSYS_TRACE_LEGACY");
handle_deprecated_setting("ROCPROFSYS_USE_TIMEMORY", "ROCPROFSYS_PROFILE");
scope::get_fields()[scope::flat::value] = _config->get_flat_profile();
@@ -1127,7 +1136,8 @@ configure_mode_settings(const std::shared_ptr<settings>& _config)
if(get_mode() == Mode::Coverage)
{
set_default_setting_value("ROCPROFSYS_USE_CODE_COVERAGE", true);
_set("ROCPROFSYS_TRACE", false);
_set("ROCPROFSYS_TRACE_LEGACY", false);
_set("ROCPROFSYS_TRACE_CACHED", false);
_set("ROCPROFSYS_PROFILE", false);
_set("ROCPROFSYS_USE_CAUSAL", false);
_set("ROCPROFSYS_USE_AMD_SMI", false);
@@ -1140,7 +1150,8 @@ configure_mode_settings(const std::shared_ptr<settings>& _config)
else if(get_mode() == Mode::Causal)
{
_set("ROCPROFSYS_USE_CAUSAL", true);
_set("ROCPROFSYS_TRACE", false);
_set("ROCPROFSYS_TRACE_LEGACY", false);
_set("ROCPROFSYS_TRACE_CACHED", false);
_set("ROCPROFSYS_PROFILE", false);
_set("ROCPROFSYS_USE_SAMPLING", false);
_set("ROCPROFSYS_USE_PROCESS_SAMPLING", false);
@@ -1836,7 +1847,7 @@ get_verbose()
bool&
get_use_perfetto()
{
static auto _v = get_config()->at("ROCPROFSYS_TRACE");
static auto _v = get_config()->at("ROCPROFSYS_TRACE_LEGACY");
return static_cast<tim::tsettings<bool>&>(*_v).get();
}
@@ -2144,11 +2155,12 @@ get_perfetto_backend()
std::string
get_perfetto_output_filename()
{
static auto _v = get_config()->find("ROCPROFSYS_PERFETTO_FILE");
auto _val = static_cast<tim::tsettings<std::string>&>(*_v->second).get();
auto _pos_dir = _val.find_last_of('/');
auto _dir = std::string{};
auto _ext = std::string{ "proto" };
static auto _v = get_config()->find("ROCPROFSYS_PERFETTO_FILE");
auto _val = static_cast<tim::tsettings<std::string>&>(*_v->second).get();
auto _pos_dir = _val.find_last_of('/');
auto _dir = std::string{};
auto _ext = std::string{ "proto" };
if(_pos_dir != std::string::npos)
{
_dir = _val.substr(0, _pos_dir + 1);
@@ -2161,12 +2173,38 @@ get_perfetto_output_filename()
_val = _val.substr(0, _pos_ext);
}
ROCPROFSYS_BASIC_VERBOSE_F(
2, "[get_perfetto_output_filename] Parsed: dir='%s', basename='%s', ext='%s'\n",
_dir.c_str(), _val.c_str(), _ext.c_str());
ROCPROFSYS_BASIC_VERBOSE_F(
2, "[get_perfetto_output_filename] settings::output_path()='%s'\n",
settings::output_path().c_str());
ROCPROFSYS_BASIC_VERBOSE_F(
2, "[get_perfetto_output_filename] settings::output_prefix()='%s'\n",
settings::output_prefix().c_str());
auto _cfg = settings::compose_filename_config{ settings::use_output_suffix(),
settings::default_process_suffix(),
false, _dir };
_val = settings::compose_output_filename(_val, _ext, _cfg);
ROCPROFSYS_BASIC_VERBOSE_F(
2, "[get_perfetto_output_filename] After compose_output_filename: '%s'\n",
_val.c_str());
if(!_val.empty() && _val.at(0) != '/')
return settings::format(JOIN('/', "%env{PWD}%", _val), get_config()->get_tag());
{
auto _result =
settings::format(JOIN('/', "%env{PWD}%", _val), get_config()->get_tag());
ROCPROFSYS_BASIC_VERBOSE_F(
2, "[get_perfetto_output_filename] Path is relative, prepending PWD: '%s'\n",
_result.c_str());
return _result;
}
ROCPROFSYS_BASIC_VERBOSE_F(
2, "[get_perfetto_output_filename] Path is absolute, returning: '%s'\n",
_val.c_str());
return _val;
}
@@ -2426,8 +2464,20 @@ get_perfetto_output_filename_with_suffix(std::string_view suffix)
static auto _v = get_config()->find("ROCPROFSYS_PERFETTO_FILE");
auto _val = static_cast<tim::tsettings<std::string>&>(*_v->second).get();
ROCPROFSYS_BASIC_VERBOSE_F(2,
"[get_perfetto_output_filename_with_suffix] Initial "
"ROCPROFSYS_PERFETTO_FILE='%s', suffix='%s'\n",
_val.c_str(), std::string{ suffix }.c_str());
// If absolute path is provided, return it as-is
if(!_val.empty() && _val.at(0) == '/') return _val;
if(!_val.empty() && _val.at(0) == '/')
{
ROCPROFSYS_BASIC_VERBOSE_F(
2,
"[get_perfetto_output_filename_with_suffix] Absolute path, returning: '%s'\n",
_val.c_str());
return _val;
}
auto _pos_dir = _val.find_last_of('/');
auto _dir = std::string{};
@@ -2451,6 +2501,15 @@ get_perfetto_output_filename_with_suffix(std::string_view suffix)
bool _explicitly_set =
(_v->second->get_environ_updated() || _v->second->get_config_updated());
ROCPROFSYS_BASIC_VERBOSE_F(
2,
"[get_perfetto_output_filename_with_suffix] Parsed: dir='%s', basename='%s', "
"ext='%s', explicitly_set=%s\n",
_dir.c_str(), _val.c_str(), _ext.c_str(), _explicitly_set ? "true" : "false");
ROCPROFSYS_BASIC_VERBOSE_F(
2, "[get_perfetto_output_filename_with_suffix] settings::output_path()='%s'\n",
settings::output_path().c_str());
auto _cfg = settings::compose_filename_config{
!_explicitly_set && !suffix.empty(), // use_suffix only if not explicitly set
suffix, // suffix value
@@ -2459,9 +2518,27 @@ get_perfetto_output_filename_with_suffix(std::string_view suffix)
};
_val = settings::compose_output_filename(_val, _ext, _cfg);
if(!_val.empty() && _val.at(0) != '/')
return settings::format(JOIN('/', "%env{PWD}%", _val), get_config()->get_tag());
ROCPROFSYS_BASIC_VERBOSE_F(2,
"[get_perfetto_output_filename_with_suffix] After "
"compose_output_filename: '%s'\n",
_val.c_str());
if(!_val.empty() && _val.at(0) != '/')
{
auto _result =
settings::format(JOIN('/', "%env{PWD}%", _val), get_config()->get_tag());
ROCPROFSYS_BASIC_VERBOSE_F(2,
"[get_perfetto_output_filename_with_suffix] Path is "
"relative, prepending PWD: '%s'\n",
_result.c_str());
return _result;
}
ROCPROFSYS_BASIC_VERBOSE_F(
2,
"[get_perfetto_output_filename_with_suffix] Path is absolute, returning: '%s'\n",
_val.c_str());
return _val;
}
@@ -243,6 +243,7 @@ post_process(tim::manager* _timemory_manager, bool& _perfetto_output_error)
#endif
auto _filename = config::get_perfetto_output_filename();
if(!trace_data.empty())
{
operation::file_output_message<tim::project::rocprofsys> _fom{};
@@ -668,9 +668,40 @@ perfetto_processor_t::handle(const region_sample& _rs)
annotate_perfetto(ctx, annotations);
};
tracing::push_perfetto_ts(category::rocm{}, _name.c_str(), _beg_ts,
::perfetto::Flow::ProcessScoped(_corr_id), add_annotations);
tracing::pop_perfetto_ts(category::rocm{}, _name.c_str(), _end_ts);
auto emit_trace = [&](auto category_tag) {
using CategoryT = decltype(category_tag);
tracing::push_perfetto_ts(CategoryT{}, _name.c_str(), _beg_ts,
::perfetto::Flow::ProcessScoped(_corr_id),
add_annotations);
tracing::pop_perfetto_ts(CategoryT{}, _name.c_str(), _end_ts);
};
auto try_category = [&](auto category_tag) {
using CategoryT = decltype(category_tag);
if(_category == trait::name<CategoryT>::value)
{
emit_trace(category_tag);
return true;
}
return false;
};
bool dispatched =
(try_category(category::host{}) || try_category(category::user{}) ||
try_category(category::python{}) || try_category(category::mpi{}) ||
try_category(category::pthread{}) || try_category(category::kokkos{}) ||
try_category(category::rocm_hip_api{}) ||
try_category(category::rocm_hsa_api{}) ||
try_category(category::rocm_marker_api{}) ||
try_category(category::rocm_rccl{}) ||
try_category(category::rocm_rocdecode_api{}) ||
try_category(category::rocm_rocjpeg_api{}) || try_category(category::vaapi{}));
if(!dispatched)
{
// Default to rocm category for backward compatibility
emit_trace(category::rocm{});
}
}
void
@@ -894,32 +925,6 @@ perfetto_processor_t::handle([[maybe_unused]] const pmc_event_with_sample& _pmc)
void
perfetto_processor_t::handle([[maybe_unused]] const amd_smi_sample& _amd_smi)
{
// using amd_smi_gfx_track = perfetto_counter_track<category::amd_smi_gfx_busy>;
// using amd_smi_umc_track = perfetto_counter_track<category::amd_smi_umc_busy>;
// using amd_smi_mm_track = perfetto_counter_track<category::amd_smi_mm_busy>;
// using amd_smi_temp_track = perfetto_counter_track<category::amd_smi_temp>;
// using amd_smi_power_track = perfetto_counter_track<category::amd_smi_power>;
// using amd_smi_mem_track = perfetto_counter_track<category::amd_smi_memory_usage>;
// using amd_smi_vcn_track = perfetto_counter_track<category::amd_smi_vcn_activity>;
// using amd_smi_jpeg_track =
// perfetto_counter_track<category::amd_smi_jpeg_activity>; using
// amd_smi_xgmi_link_width_track =
// perfetto_counter_track<category::amd_smi_xgmi_link_width>;
// using amd_smi_xgmi_link_speed_track =
// perfetto_counter_track<category::amd_smi_xgmi_link_speed>;
// using amd_smi_xgmi_read_track =
// perfetto_counter_track<category::amd_smi_xgmi_read_data>;
// using amd_smi_xgmi_write_track =
// perfetto_counter_track<category::amd_smi_xgmi_write_data>;
// using amd_smi_pcie_link_width_track =
// perfetto_counter_track<category::amd_smi_pcie_link_width>;
// using amd_smi_pcie_link_speed_track =
// perfetto_counter_track<category::amd_smi_pcie_link_speed>;
// using amd_smi_pcie_bandwidth_acc_track =
// perfetto_counter_track<category::amd_smi_pcie_bandwidth_acc>;
// using amd_smi_pcie_bandwidth_inst_track =
// perfetto_counter_track<category::amd_smi_pcie_bandwidth_inst>;
// Use the shared gpu_metrics_t from core/gpu_metrics.hpp
using gpu_metrics_t = gpu::gpu_metrics_t;
@@ -937,36 +942,6 @@ perfetto_processor_t::handle([[maybe_unused]] const amd_smi_sample& _amd_smi)
auto _ts = _amd_smi.timestamp;
auto _device_id = _amd_smi.device_id;
// auto setup_tracks = [&]() {
// if(amd_smi_gfx_track::exists(_device_id)) return;
// auto make_track_name = [&](const char* metric) {
// return JOIN(" ", "GPU", JOIN("", '[', _device_id, ']'), metric, "(S)");
// };
// if(is_busy_enabled)
// {
// amd_smi_gfx_track::emplace(_device_id, make_track_name("GFX Busy"), "%");
// amd_smi_umc_track::emplace(_device_id, make_track_name("UMC Busy"), "%");
// amd_smi_mm_track::emplace(_device_id, make_track_name("MM Busy"), "%");
// }
// if(is_temp_enabled)
// {
// amd_smi_temp_track::emplace(_device_id, make_track_name("Temperature"),
// "deg C");
// }
// if(is_power_enabled)
// {
// amd_smi_power_track::emplace(_device_id, make_track_name("Power"), "W");
// }
// if(is_mem_usage_enabled)
// {
// amd_smi_mem_track::emplace(_device_id, make_track_name("Memory Usage"),
// "MB");
// }
// };
// setup_tracks();
setup_amd_smi_tracks(_device_id, is_busy_enabled, is_temp_enabled, is_power_enabled,
is_mem_usage_enabled);
@@ -1013,6 +988,14 @@ perfetto_processor_t::handle([[maybe_unused]] const amd_smi_sample& _amd_smi)
using Category = std::decay_t<decltype(category)>;
const char* metric_name = nullptr;
if constexpr(std::is_same_v<Category, category::amd_smi_vcn_activity>)
metric_name = "VCN Activity";
else if constexpr(std::is_same_v<Category, category::amd_smi_jpeg_activity>)
metric_name = "JPEG Activity";
else
metric_name = trait::name<Category>::value;
for(size_t i = 0; i < data.size(); ++i)
{
const auto value = data[i];
@@ -1023,16 +1006,14 @@ perfetto_processor_t::handle([[maybe_unused]] const amd_smi_sample& _amd_smi)
{
// Per-XCP format
track_name = JOIN(
" ", "GPU", JOIN("", '[', _device_id, ']'),
trait::name<Category>::value,
" ", "GPU", JOIN("", '[', _device_id, ']'), metric_name,
JOIN("", "XCP_", _idx.value(), ": [", (i < 10 ? "0" : ""), i, ']'),
"(S)");
}
else
{
// Device-level format
track_name = JOIN(" ", "GPU", JOIN("", '[', _device_id, ']'),
trait::name<Category>::value,
track_name = JOIN(" ", "GPU", JOIN("", '[', _device_id, ']'), metric_name,
JOIN("", "[", (i < 10 ? "0" : ""), i, ']'), "(S)");
}
@@ -103,6 +103,7 @@ extern "C"
void rocprofsys_set_mpi_hidden(bool, bool) ROCPROFSYS_HIDDEN_API;
void rocprofsys_push_trace_hidden(const char*) ROCPROFSYS_HIDDEN_API;
void rocprofsys_pop_trace_hidden(const char*) ROCPROFSYS_HIDDEN_API;
void rocprofsys_flush_pending_region_cache_hidden() ROCPROFSYS_HIDDEN_API;
void rocprofsys_push_region_hidden(const char*) ROCPROFSYS_HIDDEN_API;
void rocprofsys_pop_region_hidden(const char*) ROCPROFSYS_HIDDEN_API;
void rocprofsys_push_category_region_hidden(rocprofsys_category_t, const char*,
@@ -899,11 +899,12 @@ rocprofsys_finalize_hidden(void)
#endif
ROCPROFSYS_DEBUG_F("Stopping and destroying instrumentation bundles...\n");
for(size_t i = 0; i < thread_info::get_peak_num_threads(); ++i)
auto* _bundles = instrumentation_bundles::get();
for(size_t i = 0; _bundles && i < thread_info::get_peak_num_threads(); ++i)
{
if(!instrumentation_bundles::get()) continue;
if(i >= _bundles->size()) continue;
const auto& _info = thread_info::get(i, SequentTID);
auto& itr = instrumentation_bundles::get()->at(i);
auto& itr = _bundles->at(i);
while(itr != nullptr && !itr->empty())
{
int _lvl = 1;
@@ -1026,6 +1027,11 @@ rocprofsys_finalize_hidden(void)
tracing::copy_timemory_hash_ids();
// Flush any pending region cache entries (e.g., main entry point that wasn't
// explicitly stopped before finalization)
ROCPROFSYS_DEBUG_F("Flushing pending region cache entries...\n");
rocprofsys_flush_pending_region_cache_hidden();
bool _perfetto_output_error = false;
if(get_use_perfetto())
{
@@ -120,6 +120,31 @@ cache_stop(const char* name)
rocprofsys::trait::name<CategoryT>::value);
}
}
/// Flush all pending cached entries for this thread.
/// Called during finalization to ensure entries that were started but not stopped
/// (e.g., main entry point) are written to the trace cache.
inline void
flush_pending_cached_entries()
{
const auto end_ts = static_cast<timestamp_t>(rocprofsys::comp::wall_clock::record());
uint64_t thread_id = 0;
const auto& extended_info = rocprofsys::thread_info::get(std::this_thread::get_id());
if(extended_info.has_value() && extended_info->index_data.has_value())
{
constexpr size_t UNKNOWN_TIME = 0;
thread_id = extended_info->index_data->system_value;
rocprofsys::trace_cache::get_metadata_registry().add_thread_info(
{ getppid(), getpid(), thread_id, UNKNOWN_TIME, UNKNOWN_TIME, "{}" });
}
for(const auto& [key, start_ts] : map_name_to_args)
{
cache_region(thread_id, key.name, start_ts, end_ts, key.category);
}
map_name_to_args.clear();
}
} // namespace
namespace tim
@@ -533,12 +533,22 @@ void
cache_region(const rocprofiler_callback_tracing_record_t* record,
const rocprofiler_timestamp_t start_timestamp,
const rocprofiler_timestamp_t end_timestamp, const std::string& call_stack,
const std::string& args_str, const std::string& category)
const std::string& args_str, const std::string& category,
std::string_view name = {})
{
auto callback_tracing_info =
trace_cache::get_metadata_registry().get_callback_tracing_info();
auto _name = std::string{ callback_tracing_info.at(record->kind, record->operation) };
// Use provided name if available, otherwise fall back to API operation name
std::string _name;
if(name.empty())
{
auto callback_tracing_info =
trace_cache::get_metadata_registry().get_callback_tracing_info();
_name = std::string{ callback_tracing_info.at(record->kind, record->operation) };
}
else
{
_name = std::string{ name };
}
trace_cache::get_buffer_storage().store(trace_cache::region_sample{
record->thread_id, _name.c_str(), record->correlation_id.internal,
@@ -814,7 +824,7 @@ tool_tracing_callback_stop(
cache_add_thread_info(record.thread_id);
std::string args_str = get_args_string(args);
cache_region(&record, _beg_ts, _end_ts, call_stack.dump(), args_str,
trait::name<CategoryT>::value);
trait::name<CategoryT>::value, _name);
}
}
@@ -31,6 +31,7 @@
#include "core/state.hpp"
#include "core/timemory.hpp"
#include "core/utility.hpp"
#include "library/thread_data_growth.hpp"
#include "library/thread_deleter.hpp"
#include <timemory/utility/macros.hpp>
@@ -54,15 +55,6 @@ using instrumentation_bundle_t =
// allocator for instrumentation_bundle_t
using bundle_allocator_t = tim::data::ring_buffer_allocator<instrumentation_bundle_t>;
using grow_functor_t = int64_t (*)(int64_t);
inline auto&
grow_functors()
{
static auto _v = container::stable_vector<grow_functor_t>{};
return _v;
}
template <typename Tp>
struct base_thread_data
{
@@ -77,7 +69,16 @@ struct base_thread_data
}
return (_v) ? _v->capacity() : 0;
};
grow_functors().emplace_back(std::move(_func));
grow_functors().emplace_back(_func);
// Immediately sync this container to current peak_num_threads.
// This ensures containers instantiated after threads exceed
// max_supported_threads are properly sized.
auto _current_peak = get_current_peak_num_threads();
if(_current_peak > static_cast<int64_t>(max_supported_threads))
{
_func(_current_peak);
}
}
};
@@ -0,0 +1,63 @@
// MIT License
//
// Copyright (c) 2022-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 "core/concepts.hpp"
#include "core/containers/stable_vector.hpp"
#include <cstdint>
#include <functional>
namespace rocprofsys
{
using grow_functor_t = int64_t (*)(int64_t);
inline auto&
grow_functors()
{
static auto _v = container::stable_vector<grow_functor_t>{};
return _v;
}
inline auto&
get_peak_num_threads_callback()
{
static std::function<int64_t()> _v = []() -> int64_t {
return static_cast<int64_t>(max_supported_threads);
};
return _v;
}
inline int64_t
get_current_peak_num_threads()
{
return get_peak_num_threads_callback()();
}
inline void
set_peak_num_threads_callback(std::function<int64_t()> _cb)
{
get_peak_num_threads_callback() = std::move(_cb);
}
} // namespace rocprofsys
@@ -30,6 +30,7 @@
#include "library/causal/delay.hpp"
#include "library/runtime.hpp"
#include "library/thread_data.hpp"
#include "library/thread_data_growth.hpp"
#include <timemory/backends/threading.hpp>
#include <timemory/components/timing/backends.hpp>
@@ -111,6 +112,13 @@ init_index_data(int64_t _tid, bool _offset = false)
thread_local int64_t offset_causal_count = 0;
const auto unknown_thread = std::optional<thread_info>{};
int64_t peak_num_threads = max_supported_threads;
// Register callback to allow thread_data containers to query peak_num_threads
// when they are instantiated, ensuring late-instantiated containers are properly sized.
const auto peak_num_threads_callback_registered = []() {
set_peak_num_threads_callback([]() -> int64_t { return peak_num_threads; });
return true;
}();
} // namespace
std::string
@@ -124,6 +124,12 @@ rocprofsys_pop_trace_hidden(const char* name)
rocprofsys::component::category_region<rocprofsys::category::host>::stop(name);
}
extern "C" void
rocprofsys_flush_pending_region_cache_hidden()
{
flush_pending_cached_entries();
}
//======================================================================================//
///
///