ROCpd support [Part 1] (#279)

- Add rocpd support for
 - cpu_frequency
 - amd_smi
 - sampling
Dieser Commit ist enthalten in:
Aleksandar Djordjevic
2025-07-28 17:33:52 +02:00
committet von GitHub
Ursprung 4b4a846b58
Commit 26ae543012
49 geänderte Dateien mit 6770 neuen und 365 gelöschten Zeilen
+96 -5
Datei anzeigen
@@ -27,17 +27,22 @@
#include "api.hpp"
#include "common/setup.hpp"
#include "common/static_object.hpp"
#include "core/agent.hpp"
#include "core/agent_manager.hpp"
#include "core/categories.hpp"
#include "core/components/fwd.hpp"
#include "core/concepts.hpp"
#include "core/config.hpp"
#include "core/constraint.hpp"
#include "core/cpu.hpp"
#include "core/debug.hpp"
#include "core/defines.hpp"
#include "core/dynamic_library.hpp"
#include "core/gpu.hpp"
#include "core/locking.hpp"
#include "core/node_info.hpp"
#include "core/perfetto_fwd.hpp"
#include "core/rocpd/data_processor.hpp"
#include "core/timemory.hpp"
#include "core/utility.hpp"
#include "library/causal/data.hpp"
@@ -77,6 +82,10 @@
#include <timemory/utility/join.hpp>
#include <timemory/utility/procfs/maps.hpp>
#if ROCPROFSYS_USE_ROCM > 0
# include <rocprofiler-sdk/agent.h>
#endif
#include <atomic>
#include <chrono>
#include <csignal>
@@ -86,6 +95,7 @@
#include <pthread.h>
#include <stdexcept>
#include <string_view>
#include <unistd.h>
#include <utility>
using namespace rocprofsys;
@@ -297,6 +307,66 @@ namespace
bool _set_mpi_called = false;
std::function<void()> _preinit_callback = []() { get_preinit_bundle()->start(); };
std::vector<std::string>
read_command_line(pid_t _pid)
{
auto _cmdline = std::vector<std::string>{};
auto fcmdline = std::stringstream{};
fcmdline << "/proc/" << _pid << "/cmdline";
auto ifs = std::ifstream{ fcmdline.str().c_str() };
if(ifs)
{
std::string sarg;
while(std::getline(ifs, sarg, '\0'))
{
_cmdline.push_back(sarg);
}
ifs.close();
}
return _cmdline;
}
void
rocprofsys_preinit_rocpd()
{
auto& _data_processor = rocpd::data_processor::get_instance();
const auto& _n_info = node_info::get_instance();
auto _cmd_line = read_command_line(getpid());
auto& _agent_manager = agent_manager::get_instance();
if(_cmd_line.empty())
{
_cmd_line.emplace_back("rocprofiler-systems");
}
_data_processor.insert_node_info(
_n_info.id, _n_info.hash, _n_info.machine_id.c_str(), _n_info.system_name.c_str(),
_n_info.node_name.c_str(), _n_info.release.c_str(), _n_info.version.c_str(),
_n_info.machine.c_str(), _n_info.domain_name.c_str());
_data_processor.insert_process_info(_n_info.id, getppid(), getpid(), 0, 0, 0, 0,
_cmd_line[0].c_str(), "{}");
const auto& agents = _agent_manager.get_agents();
for(const auto& rocpd_agent : agents)
{
auto _base_id = rocpd::data_processor::get_instance().insert_agent(
_n_info.id, getpid(),
((rocpd_agent->type == agent_type::GPU) ? "GPU" : "CPU"),
rocpd_agent->node_id, rocpd_agent->logical_node_id,
rocpd_agent->logical_node_type_id, rocpd_agent->id, rocpd_agent->name.c_str(),
rocpd_agent->model_name.c_str(), rocpd_agent->vendor_name.c_str(),
rocpd_agent->product_name.c_str(), "");
rocpd_agent->base_id = _base_id;
}
}
void
rocprofsys_preinit_cpu_agents()
{
cpu::query_cpu_agents();
}
void
rocprofsys_preinit_hidden()
{
@@ -423,17 +493,17 @@ rocprofsys_init_tooling_hidden(void)
{ ROCPROFSYS_DEFAULT_ROCM_PATH }) };
#endif
static bool _once = false;
static auto _debug_init = get_debug_init();
static pid_t _once = 0;
static auto _debug_init = get_debug_init();
ROCPROFSYS_CONDITIONAL_BASIC_PRINT_F(_debug_init, "State is %s...\n",
std::to_string(get_state()).c_str());
if(get_state() != State::PreInit || get_state() == State::Init || _once)
if(get_state() != State::PreInit || get_state() == State::Init || _once == getpid())
{
return false;
}
_once = true;
_once = getpid();
ROCPROFSYS_SCOPED_THREAD_STATE(ThreadState::Internal);
@@ -460,6 +530,12 @@ rocprofsys_init_tooling_hidden(void)
auto _dtor = scope::destructor{ []() {
// if set to finalized, don't continue
if(get_state() > State::Active) return;
#if !(ROCPROFSYS_USE_ROCM > 0)
rocprofsys_preinit_cpu_agents();
#endif
if(get_use_rocpd()) rocprofsys_preinit_rocpd();
if(get_use_process_sampling())
{
ROCPROFSYS_SCOPED_SAMPLING_ON_CHILD_THREADS(false);
@@ -681,7 +757,6 @@ rocprofsys_finalize_hidden(void)
threading::remove_callback(&ensure_initialization);
bool _is_child = is_child_process();
set_thread_state(ThreadState::Completed);
// return if not active
@@ -693,6 +768,18 @@ rocprofsys_finalize_hidden(void)
}
else if(_is_child)
{
#if defined(ROCPROFSYS_USE_ROCM) && ROCPROFSYS_USE_ROCM > 0
// Flush buffered traces in case of child process
if(get_use_rocm())
{
ROCPROFSYS_VERBOSE_F(1, "Shutting down ROCm...\n");
rocprofiler_sdk::shutdown();
}
#endif
if(get_use_rocpd())
{
rocpd::data_processor::get_instance().flush();
}
set_state(State::Finalized);
std::quick_exit(EXIT_SUCCESS);
return;
@@ -983,6 +1070,10 @@ rocprofsys_finalize_hidden(void)
[](int) {});
common::destroy_static_objects();
if(get_use_rocpd())
{
rocpd::data_processor::get_instance().flush();
}
}
//======================================================================================//
+264 -143
Datei anzeigen
@@ -26,18 +26,22 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
#include "core/agent.hpp"
#if defined(NDEBUG)
# undef NDEBUG
#endif
#include "library/amd_smi.hpp"
#include "core/agent_manager.hpp"
#include "core/common.hpp"
#include "core/components/fwd.hpp"
#include "core/config.hpp"
#include "core/debug.hpp"
#include "core/gpu.hpp"
#include "core/node_info.hpp"
#include "core/perfetto.hpp"
#include "core/rocpd/data_processor.hpp"
#include "core/state.hpp"
#include "library/amd_smi.hpp"
#include "library/runtime.hpp"
#include "library/thread_info.hpp"
@@ -49,13 +53,11 @@
#include <timemory/utility/locking.hpp>
#include <cassert>
#include <chrono>
#include <ios>
#include <optional>
#include <sstream>
#include <stdexcept>
#include <string>
#include <sys/resource.h>
#include <thread>
#define ROCPROFSYS_AMD_SMI_CALL(...) \
::rocprofsys::amd_smi::check_error(__FILE__, __LINE__, __VA_ARGS__)
@@ -69,6 +71,115 @@ using sampler_instances = thread_data<bundle_t, category::amd_smi>;
namespace
{
int64_t
get_tid()
{
static thread_local auto _v = threading::get_id();
return _v;
}
rocpd::data_processor&
get_data_processor()
{
return rocpd::data_processor::get_instance();
}
void
rocpd_initialize_category()
{
get_data_processor().insert_category(ROCPROFSYS_CATEGORY_AMD_SMI,
trait::name<category::amd_smi>::value);
}
void
rocpd_initialize_smi_tracks()
{
auto& data_processor = get_data_processor();
auto& n_info = node_info::get_instance();
const auto thread_id = std::nullopt; // Internal thread ID for amd-smi
data_processor.insert_track(trait::name<category::amd_smi_mm_busy>::value, n_info.id,
getpid(), thread_id);
data_processor.insert_track(trait::name<category::amd_smi_power>::value, n_info.id,
getpid(), thread_id);
data_processor.insert_track(trait::name<category::amd_smi_temp>::value, n_info.id,
getpid(), thread_id);
data_processor.insert_track(trait::name<category::amd_smi_memory_usage>::value,
n_info.id, getpid(), thread_id);
}
void
rocpd_initialize_smi_pmc(size_t gpu_id)
{
auto& data_processor = get_data_processor();
// find the proper values for a following definitions
size_t EVENT_CODE = 0;
size_t INSTANCE_ID = 0;
const char* LONG_DESCRIPTION = "";
const char* COMPONENT = "";
const char* BLOCK = "";
const char* EXPRESSION = "";
const char* CELSIUS_DEGREES = "\u00B0C";
auto ni = node_info::get_instance();
const auto* TARGET_ARCH = "GPU";
auto& _agent_manager = agent_manager::get_instance();
auto base_id = _agent_manager.get_agent_by_id(gpu_id, agent_type::GPU).base_id;
data_processor.insert_pmc_description(
ni.id, getpid(), base_id, TARGET_ARCH, EVENT_CODE, INSTANCE_ID,
trait::name<category::amd_smi_mm_busy>::value, "Busy",
trait::name<category::amd_smi_mm_busy>::description, LONG_DESCRIPTION, COMPONENT,
"%", "ABS", BLOCK, EXPRESSION, 0, 0);
data_processor.insert_pmc_description(
ni.id, getpid(), base_id, TARGET_ARCH, EVENT_CODE, INSTANCE_ID,
trait::name<category::amd_smi_temp>::value, "Temp",
trait::name<category::amd_smi_temp>::description, LONG_DESCRIPTION, COMPONENT,
CELSIUS_DEGREES, "ABS", BLOCK, EXPRESSION, 0, 0);
data_processor.insert_pmc_description(
ni.id, getpid(), base_id, TARGET_ARCH, EVENT_CODE, INSTANCE_ID,
trait::name<category::amd_smi_power>::value, "Pow",
trait::name<category::amd_smi_power>::description, LONG_DESCRIPTION, COMPONENT,
"w", "ABS", BLOCK, EXPRESSION, 0, 0);
data_processor.insert_pmc_description(
ni.id, getpid(), base_id, TARGET_ARCH, EVENT_CODE, INSTANCE_ID,
trait::name<category::amd_smi_memory_usage>::value, "MemUsg",
trait::name<category::amd_smi_memory_usage>::description, LONG_DESCRIPTION,
COMPONENT, "MB", "ABS", BLOCK, EXPRESSION, 0, 0);
}
void
rocpd_process_smi_pmc_events(const uint32_t device_id, const amd_smi::settings& settings,
uint64_t timestamp, double busy, double temp, double power,
double usage)
{
if(!(settings.busy || settings.temp || settings.power || settings.mem_usage)) return;
auto& data_processor = get_data_processor();
auto event_id = data_processor.insert_event(ROCPROFSYS_CATEGORY_AMD_SMI, 0, 0, 0);
auto& _agent_manager = agent_manager::get_instance();
auto base_id = _agent_manager.get_agent_by_id(device_id, agent_type::GPU).base_id;
auto insert_event_and_sample = [&](bool enabled, const char* name, double value) {
if(!enabled) return;
data_processor.insert_pmc_event(event_id, base_id, name, value);
data_processor.insert_sample(name, timestamp, event_id);
};
insert_event_and_sample(settings.busy, trait::name<category::amd_smi_mm_busy>::value,
busy);
insert_event_and_sample(settings.temp, trait::name<category::amd_smi_temp>::value,
temp);
insert_event_and_sample(settings.power, trait::name<category::amd_smi_power>::value,
power);
insert_event_and_sample(settings.mem_usage,
trait::name<category::amd_smi_memory_usage>::value, usage);
}
auto&
get_settings(uint32_t _dev_id)
{
@@ -140,6 +251,8 @@ data::data(uint32_t _dev_id) { sample(_dev_id); }
void
data::sample(uint32_t _dev_id)
{
if(is_child_process()) return;
auto _ts = tim::get_clock_real_now<size_t, std::nano>();
assert(_ts < std::numeric_limits<int64_t>::max());
amdsmi_gpu_metrics_t _gpu_metrics;
@@ -168,7 +281,6 @@ data::sample(uint32_t _dev_id)
}
amdsmi_processor_handle sample_handle = gpu::get_handle_from_id(_dev_id);
ROCPROFSYS_AMDSMI_GET(get_settings(m_dev_id).busy, amdsmi_get_gpu_activity,
sample_handle, &m_busy_perc);
ROCPROFSYS_AMDSMI_GET(get_settings(m_dev_id).temp, amdsmi_get_temp_metric,
@@ -276,10 +388,15 @@ config()
*_bundle_data.at(i) = unique_ptr_t<bundle_t>{ new bundle_t{} };
}
}
data::get_initial().resize(data::device_count);
for(auto itr : data::device_list)
data::get_initial().at(itr).sample(itr);
if(get_use_rocpd())
{
rocpd_initialize_category();
rocpd_initialize_smi_tracks();
}
}
void
@@ -363,192 +480,194 @@ data::post_process(uint32_t _dev_id)
auto _settings = get_settings(_dev_id);
auto _process_perfetto = [&]() {
constexpr uint8_t AMD_SMI_METRICS_COUNT = 8;
auto _idx = std::array<uint64_t, AMD_SMI_METRICS_COUNT>{};
auto use_perfetto = get_use_perfetto();
auto use_rocpd = get_use_rocpd();
if(use_rocpd)
{
rocpd_initialize_smi_pmc(_dev_id);
}
for(auto& itr : _amd_smi)
{
using counter_track = perfetto_counter_track<data>;
if(itr.m_dev_id != _dev_id) continue;
uint64_t _ts = itr.m_ts;
if(!_thread_info->is_valid_time(_ts)) continue;
double _gfxbusy = itr.m_busy_perc.gfx_activity;
double _umcbusy = itr.m_busy_perc.umc_activity;
double _mmbusy = itr.m_busy_perc.mm_activity;
double _temp = itr.m_temp;
double _power = itr.m_power.current_socket_power;
double _usage = itr.m_mem_usage / static_cast<double>(units::megabyte);
auto setup_perfetto_counter_tracks = [&]() {
if(counter_track::exists(_dev_id)) return;
auto addendum = [&](const char* _v) {
return JOIN(" ", "GPU", _v, JOIN("", '[', _dev_id, ']'), "(S)");
};
auto addendum_blk = [&](std::size_t _i, const char* _metric,
std::size_t xcp_idx = SIZE_MAX) {
if(xcp_idx != SIZE_MAX)
{
return JOIN(
" ", "GPU", JOIN("", '[', _dev_id, ']'), _metric,
JOIN("", "XCP_", xcp_idx, ": [", (_i < 10 ? "0" : ""), _i, ']'),
"(S)");
}
else
{
return JOIN(" ", "GPU", JOIN("", '[', _dev_id, ']'), _metric,
JOIN("", "[", (_i < 10 ? "0" : ""), _i, ']'), "(S)");
}
};
{
_idx.fill(_idx.size());
uint64_t nidx = 0;
if(_settings.busy)
{
_idx.at(0) = nidx++; // GFX Busy
_idx.at(1) = nidx++; // UMC Busy
_idx.at(2) = nidx++; // MM Busy
counter_track::emplace(_dev_id, addendum("GFX Busy"), "%");
counter_track::emplace(_dev_id, addendum("UMC Busy"), "%");
counter_track::emplace(_dev_id, addendum("MM Busy"), "%");
}
if(_settings.temp) _idx.at(3) = nidx++;
if(_settings.power) _idx.at(4) = nidx++;
if(_settings.mem_usage) _idx.at(5) = nidx++;
if(_settings.vcn_activity) _idx.at(6) = nidx++;
if(_settings.jpeg_activity) _idx.at(7) = nidx++;
}
for(auto& itr : _amd_smi)
{
using counter_track = perfetto_counter_track<data>;
if(itr.m_dev_id != _dev_id) continue;
if(!counter_track::exists(_dev_id))
if(_settings.temp)
{
auto addendum = [&](const char* _v) {
return JOIN(" ", "GPU", _v, JOIN("", '[', _dev_id, ']'), "(S)");
};
auto addendum_blk = [&](std::size_t _i, const char* _metric,
std::size_t xcp_idx = SIZE_MAX) {
if(xcp_idx != SIZE_MAX)
{
return JOIN(" ", "GPU", JOIN("", '[', _dev_id, ']'), _metric,
JOIN("", "XCP_", xcp_idx, ": [", (_i < 10 ? "0" : ""),
_i, ']'),
"(S)");
}
else
{
return JOIN(" ", "GPU", JOIN("", '[', _dev_id, ']'), _metric,
JOIN("", "[", (_i < 10 ? "0" : ""), _i, ']'), "(S)");
}
};
if(_settings.busy)
counter_track::emplace(_dev_id, addendum("Temperature"), "deg C");
}
if(_settings.power)
{
counter_track::emplace(_dev_id, addendum("Current Power"), "watts");
}
if(_settings.mem_usage)
{
counter_track::emplace(_dev_id, addendum("Memory Usage"), "megabytes");
}
if(_settings.vcn_activity)
{
if(itr.m_xcp_metrics.empty())
{
counter_track::emplace(_dev_id, addendum("GFX Busy"), "%");
counter_track::emplace(_dev_id, addendum("UMC Busy"), "%");
counter_track::emplace(_dev_id, addendum("MM Busy"), "%");
ROCPROFSYS_VERBOSE(
1, "No VCN activity data collected from device %u\n", _dev_id);
}
if(_settings.temp)
counter_track::emplace(_dev_id, addendum("Temperature"), "deg C");
if(_settings.power)
counter_track::emplace(_dev_id, addendum("Current Power"), "watts");
if(_settings.mem_usage)
counter_track::emplace(_dev_id, addendum("Memory Usage"),
"megabytes");
if(_settings.vcn_activity)
else if(gpu::is_vcn_activity_supported(_dev_id))
{
if(itr.m_xcp_metrics.empty())
{
ROCPROFSYS_VERBOSE(
1, "No VCN activity data collected from device %u\n",
_dev_id);
}
else if(gpu::is_vcn_activity_supported(_dev_id))
{
// For VCN activity, use simple indexing
for(std::size_t i = 0;
i < std::size(itr.m_xcp_metrics[0].vcn_busy); ++i)
counter_track::emplace(_dev_id,
addendum_blk(i, "VCN Activity"), "%");
}
else
{
for(std::size_t xcp = 0; xcp < std::size(itr.m_xcp_metrics);
++xcp)
{
for(std::size_t i = 0;
i < std::size(itr.m_xcp_metrics[xcp].vcn_busy); ++i)
{
counter_track::emplace(
_dev_id, addendum_blk(i, "VCN Activity", xcp), "%");
}
}
}
// For VCN activity, use simple indexing
for(std::size_t i = 0; i < std::size(itr.m_xcp_metrics[0].vcn_busy);
++i)
counter_track::emplace(_dev_id, addendum_blk(i, "VCN Activity"),
"%");
}
if(_settings.jpeg_activity)
else
{
if(itr.m_xcp_metrics.empty())
for(std::size_t xcp = 0; xcp < std::size(itr.m_xcp_metrics); ++xcp)
{
ROCPROFSYS_VERBOSE(
1, "No JPEG activity data collected from device %u\n",
_dev_id);
}
else if(gpu::is_jpeg_activity_supported(_dev_id))
{
// For JPEG activity, use simple indexing
for(std::size_t i = 0;
i < std::size(itr.m_xcp_metrics[0].jpeg_busy); ++i)
counter_track::emplace(_dev_id,
addendum_blk(i, "JPEG Activity"), "%");
}
else
{
for(std::size_t xcp = 0; xcp < std::size(itr.m_xcp_metrics);
++xcp)
i < std::size(itr.m_xcp_metrics[xcp].vcn_busy); ++i)
{
for(std::size_t i = 0;
i < std::size(itr.m_xcp_metrics[xcp].jpeg_busy); ++i)
counter_track::emplace(
_dev_id, addendum_blk(i, "JPEG Activity", xcp), "%");
counter_track::emplace(
_dev_id, addendum_blk(i, "VCN Activity", xcp), "%");
}
}
}
}
uint64_t _ts = itr.m_ts;
if(!_thread_info->is_valid_time(_ts)) continue;
if(_settings.jpeg_activity)
{
if(itr.m_xcp_metrics.empty())
{
ROCPROFSYS_VERBOSE(
1, "No JPEG activity data collected from device %u\n", _dev_id);
}
else if(gpu::is_jpeg_activity_supported(_dev_id))
{
for(std::size_t i = 0; i < std::size(itr.m_xcp_metrics[0].jpeg_busy);
++i)
counter_track::emplace(_dev_id, addendum_blk(i, "JPEG Activity"),
"%");
}
else
{
for(std::size_t xcp = 0; xcp < std::size(itr.m_xcp_metrics); ++xcp)
{
for(std::size_t i = 0;
i < std::size(itr.m_xcp_metrics[xcp].jpeg_busy); ++i)
counter_track::emplace(
_dev_id, addendum_blk(i, "JPEG Activity", xcp), "%");
}
}
}
};
double _gfxbusy = itr.m_busy_perc.gfx_activity;
double _umcbusy = itr.m_busy_perc.umc_activity;
double _mmbusy = itr.m_busy_perc.mm_activity;
double _temp = itr.m_temp;
double _power = itr.m_power.current_socket_power;
double _usage = itr.m_mem_usage / static_cast<double>(units::megabyte);
auto write_perfetto_metrics = [&]() {
size_t track_index = 0;
if(_settings.busy)
{
TRACE_COUNTER("device_busy_gfx", counter_track::at(_dev_id, _idx.at(0)),
_ts, _gfxbusy);
TRACE_COUNTER("device_busy_umc", counter_track::at(_dev_id, _idx.at(1)),
_ts, _umcbusy);
TRACE_COUNTER("device_busy_mm", counter_track::at(_dev_id, _idx.at(2)),
TRACE_COUNTER("device_busy_gfx",
counter_track::at(_dev_id, track_index++), _ts, _gfxbusy);
TRACE_COUNTER("device_busy_umc",
counter_track::at(_dev_id, track_index++), _ts, _umcbusy);
TRACE_COUNTER("device_busy_mm", counter_track::at(_dev_id, track_index++),
_ts, _mmbusy);
}
if(_settings.temp)
TRACE_COUNTER("device_temp", counter_track::at(_dev_id, _idx.at(3)), _ts,
_temp);
{
TRACE_COUNTER("device_temp", counter_track::at(_dev_id, track_index++),
_ts, _temp);
}
if(_settings.power)
TRACE_COUNTER("device_power", counter_track::at(_dev_id, _idx.at(4)), _ts,
_power);
{
TRACE_COUNTER("device_power", counter_track::at(_dev_id, track_index++),
_ts, _power);
}
if(_settings.mem_usage)
{
TRACE_COUNTER("device_memory_usage",
counter_track::at(_dev_id, _idx.at(5)), _ts, _usage);
counter_track::at(_dev_id, track_index++), _ts, _usage);
}
if(_settings.vcn_activity && !itr.m_xcp_metrics.empty())
{
uint64_t idx = _idx.at(6);
// Iterate over all XCPs and their VCN busy/activity values
for(const auto& metrics : itr.m_xcp_metrics)
{
for(const auto& vcn_val : metrics.vcn_busy)
{
TRACE_COUNTER("device_vcn_activity",
counter_track::at(_dev_id, idx), _ts, vcn_val);
++idx;
counter_track::at(_dev_id, track_index++), _ts,
vcn_val);
}
}
}
if(_settings.jpeg_activity && !itr.m_xcp_metrics.empty())
{
uint64_t idx = _idx.at(7);
// Calculate total VCN metrics to properly offset JPEG metrics index
if(_settings.vcn_activity)
{
size_t total_vcn_metrics = 0;
for(const auto& metrics : itr.m_xcp_metrics)
total_vcn_metrics += metrics.vcn_busy.size();
if(total_vcn_metrics > 0) idx += (total_vcn_metrics - 1);
}
// Iterate over all XCPs and their JPEG busy/activity values
for(const auto& metrics : itr.m_xcp_metrics)
{
for(const auto& jpeg_val : metrics.jpeg_busy)
{
TRACE_COUNTER("device_jpeg_activity",
counter_track::at(_dev_id, idx), _ts, jpeg_val);
++idx;
counter_track::at(_dev_id, track_index++), _ts,
jpeg_val);
}
}
}
}
};
};
if(get_use_perfetto()) _process_perfetto();
if(use_perfetto)
{
setup_perfetto_counter_tracks();
write_perfetto_metrics();
}
if(use_rocpd)
{
rocpd_process_smi_pmc_events(_dev_id, _settings, _ts, _mmbusy, _temp, _power,
_usage);
}
}
}
//--------------------------------------------------------------------------------------//
@@ -573,7 +692,7 @@ setup()
ROCPROFSYS_VERBOSE_F(0, "AMD SMI version: %u.%u.%u - str: %s.\n", _version.major,
_version.minor, _version.release, _version.build);
data::device_count = gpu::get_processor_count();
data::device_count = gpu::device_count();
auto _devices_v = get_sampling_gpus();
for(auto& itr : _devices_v)
@@ -668,7 +787,6 @@ setup()
}
is_initialized() = true;
data::setup();
} catch(std::runtime_error& _e)
{
@@ -705,7 +823,10 @@ void
post_process()
{
for(auto itr : data::device_list)
{
ROCPROFSYS_VERBOSE(2, "Post-processing amd-smi data for device: %d", itr);
data::post_process(itr);
}
}
uint32_t
@@ -21,10 +21,14 @@
// SOFTWARE.
#include "library/components/backtrace_metrics.hpp"
#include "core/agent.hpp"
#include "core/agent_manager.hpp"
#include "core/components/fwd.hpp"
#include "core/config.hpp"
#include "core/debug.hpp"
#include "core/node_info.hpp"
#include "core/perfetto.hpp"
#include "core/rocpd/data_processor.hpp"
#include "library/components/ensure_storage.hpp"
#include "library/ptl.hpp"
#include "library/runtime.hpp"
@@ -137,6 +141,12 @@ backtrace_metrics::get_hw_counter_labels(int64_t _tid)
return (_v) ? *_v : std::vector<std::string>{};
}
rocpd::data_processor&
get_data_processor()
{
return rocpd::data_processor::get_instance();
}
void
backtrace_metrics::start()
{}
@@ -327,6 +337,228 @@ backtrace_metrics::fini_perfetto(int64_t _tid, valid_array_t _valid)
}
}
void
rocpd_init_categories()
{
static bool _is_initialized = false;
if(_is_initialized) return;
get_data_processor().insert_category(
category_enum_id<category::thread_cpu_time>::value,
trait::name<category::thread_cpu_time>::value);
get_data_processor().insert_category(
category_enum_id<category::thread_peak_memory>::value,
trait::name<category::thread_peak_memory>::value);
get_data_processor().insert_category(
category_enum_id<category::thread_context_switch>::value,
trait::name<category::thread_context_switch>::value);
get_data_processor().insert_category(
category_enum_id<category::thread_page_fault>::value,
trait::name<category::thread_page_fault>::value);
get_data_processor().insert_category(
category_enum_id<category::thread_hardware_counter>::value,
trait::name<category::thread_hardware_counter>::value);
_is_initialized = true;
}
template <typename Category>
void
rocpd_init_tracks(int64_t _tid)
{
auto& data_processor = get_data_processor();
auto& n_info = node_info::get_instance();
const auto& t_info = thread_info::get(_tid, SequentTID);
auto _tid_name = JOIN("", '[', _tid, ']');
auto thread_idx = data_processor.insert_thread_info(
n_info.id, getppid(), getpid(), t_info->index_data->system_value,
JOIN(" ", "Thread", _tid).c_str(), t_info->get_start(), t_info->get_stop(), "{}");
if constexpr(std::is_same_v<Category, category::thread_hardware_counter>)
{
// Initialize hw_counter_tracks and create one track for each hardware counter
auto _hw_cnt_labels = *get_papi_labels(_tid);
for(auto& itr : _hw_cnt_labels)
{
std::string _desc = tim::papi::get_event_info(itr).short_descr;
if(_desc.empty()) _desc = itr;
ROCPROFSYS_CI_THROW(_desc.empty(), "Empty description for %s\n", itr.c_str());
std::string track_name = JOIN(' ', "Thread", _desc, _tid_name, "(S)");
data_processor.insert_track(track_name.c_str(), n_info.id, getpid(),
thread_idx, "{}");
}
}
else
data_processor.insert_track(
JOIN('_', trait::name<Category>::value, _tid_name).c_str(), n_info.id,
getpid(), thread_idx, "{}");
}
template <typename Category>
void
rocpd_initialize_backtrace_metrics_pmc(size_t dev_id, const char* units, int64_t _tid)
{
auto& data_processor = get_data_processor();
auto _tid_name = JOIN("", '[', _tid, ']');
size_t EVENT_CODE = 0;
size_t INSTANCE_ID = 0;
const char* LONG_DESCRIPTION = "";
const char* COMPONENT = "";
const char* BLOCK = "";
const char* EXPRESSION = "";
auto ni = node_info::get_instance();
const auto* TARGET_ARCH = "CPU";
auto& _agent_manager = agent_manager::get_instance();
auto _base_id = _agent_manager.get_agent_by_id(dev_id, agent_type::CPU).base_id;
if constexpr(std::is_same_v<Category, category::thread_hardware_counter>)
{
auto _hw_cnt_labels = *get_papi_labels(_tid);
for(auto& itr : _hw_cnt_labels)
{
std::string _desc = tim::papi::get_event_info(itr).short_descr;
if(_desc.empty()) _desc = itr;
ROCPROFSYS_CI_THROW(_desc.empty(), "Empty description for %s\n", itr.c_str());
std::string track_name = JOIN(' ', "Thread", _desc, _tid_name, "(S)");
data_processor.insert_pmc_description(
ni.id, getpid(), _base_id, TARGET_ARCH, EVENT_CODE, INSTANCE_ID,
track_name.c_str(), trait::name<Category>::value,
trait::name<Category>::description, LONG_DESCRIPTION, COMPONENT, units,
"ABS", BLOCK, EXPRESSION, 0, 0);
}
}
else
data_processor.insert_pmc_description(
ni.id, getpid(), _base_id, TARGET_ARCH, EVENT_CODE, INSTANCE_ID,
JOIN("_", trait::name<Category>::value, _tid_name).c_str(),
trait::name<Category>::value, trait::name<Category>::description,
LONG_DESCRIPTION, COMPONENT, units, "ABS", BLOCK, EXPRESSION, 0, 0);
}
template <typename Category, typename Value>
void
rocpd_process_backtrace_metrics_events(const uint32_t device_id, uint64_t timestamp,
Value value, int64_t _tid)
{
auto& data_processor = get_data_processor();
auto _tid_name = JOIN("", '[', _tid, ']');
auto event_id =
data_processor.insert_event(category_enum_id<Category>::value, 0, 0, 0);
auto& agent_mngr = agent_manager::get_instance();
auto base_id = agent_mngr.get_agent_by_id(device_id, agent_type::CPU).base_id;
auto insert_event_and_sample = [&](const char* name, double _value) {
data_processor.insert_pmc_event(event_id, base_id, name, _value);
data_processor.insert_sample(name, timestamp, event_id);
};
if constexpr(std::is_same_v<Category, category::thread_hardware_counter>)
{
auto _hw_cnt_labels = *get_papi_labels(_tid);
const auto& _hw_counters =
static_cast<backtrace_metrics::hw_counter_data_t>(value);
for(size_t i = 0; i < _hw_cnt_labels.size() && i < _hw_counters.size(); ++i)
{
std::string _desc = tim::papi::get_event_info(_hw_cnt_labels[i]).short_descr;
if(_desc.empty()) _desc = _hw_cnt_labels[i];
std::string track_name = JOIN(' ', "Thread", _desc, _tid_name, "(S)");
insert_event_and_sample(track_name.c_str(), _hw_counters.at(i));
}
}
else
insert_event_and_sample(
JOIN("_", trait::name<Category>::value, _tid_name).c_str(), value);
}
void
backtrace_metrics::init_rocpd(int64_t _tid, valid_array_t _valid)
{
rocpd_init_categories();
if(get_valid(category::thread_cpu_time{}, _valid))
{
rocpd_init_tracks<category::thread_cpu_time>(_tid);
rocpd_initialize_backtrace_metrics_pmc<category::thread_cpu_time>(0, "sec", _tid);
}
if(get_valid(category::thread_peak_memory{}, _valid))
{
rocpd_init_tracks<category::thread_peak_memory>(_tid);
rocpd_initialize_backtrace_metrics_pmc<category::thread_peak_memory>(0, "MB",
_tid);
}
if(get_valid(category::thread_context_switch{}, _valid))
{
rocpd_init_tracks<category::thread_context_switch>(_tid);
rocpd_initialize_backtrace_metrics_pmc<category::thread_context_switch>(0, "",
_tid);
}
if(get_valid(category::thread_page_fault{}, _valid))
{
rocpd_init_tracks<category::thread_page_fault>(_tid);
rocpd_initialize_backtrace_metrics_pmc<category::thread_page_fault>(0, "", _tid);
}
if(get_valid(type_list<hw_counters>{}, _valid) &&
get_valid(category::thread_hardware_counter{}, _valid))
{
rocpd_init_tracks<category::thread_hardware_counter>(_tid);
rocpd_initialize_backtrace_metrics_pmc<category::thread_hardware_counter>(0, "",
_tid);
}
}
void
backtrace_metrics::fini_rocpd(int64_t _tid, valid_array_t _valid)
{
const auto& _thread_info = thread_info::get(_tid, SequentTID);
ROCPROFSYS_CI_THROW(!_thread_info, "Error! missing thread info for tid=%li\n", _tid);
if(!_thread_info) return;
uint64_t _ts = _thread_info->get_stop();
if(get_valid(category::thread_cpu_time{}, _valid))
{
rocpd_process_backtrace_metrics_events<category::thread_cpu_time, double>(
0, _ts, 0, _tid);
}
if(get_valid(category::thread_peak_memory{}, _valid))
{
rocpd_process_backtrace_metrics_events<category::thread_peak_memory, double>(
0, _ts, 0, _tid);
}
if(get_valid(category::thread_context_switch{}, _valid))
{
rocpd_process_backtrace_metrics_events<category::thread_context_switch, int64_t>(
0, _ts, 0, _tid);
}
if(get_valid(category::thread_page_fault{}, _valid))
{
rocpd_process_backtrace_metrics_events<category::thread_page_fault, int64_t>(
0, _ts, 0, _tid);
}
if(get_valid(type_list<hw_counters>{}, _valid) &&
get_valid(category::thread_hardware_counter{}, _valid))
{
auto _hw_cnt_labels = *get_papi_labels(_tid);
hw_counter_data_t zero_counters{};
zero_counters.fill(0.0);
rocpd_process_backtrace_metrics_events<category::thread_hardware_counter,
hw_counter_data_t>(0, _ts, zero_counters,
_tid);
}
}
backtrace_metrics&
backtrace_metrics::operator-=(const backtrace_metrics& _rhs)
{
@@ -407,6 +639,43 @@ backtrace_metrics::post_process_perfetto(int64_t _tid, uint64_t _ts) const
}
}
}
void
backtrace_metrics::post_process_rocpd(int64_t _tid, uint64_t _ts) const
{
auto is_category_enabled = [&](const auto& _category) { return (*this)(_category); };
if(is_category_enabled(category::thread_cpu_time{}))
{
rocpd_process_backtrace_metrics_events<category::thread_cpu_time, double>(
0, _ts, m_cpu / units::sec, _tid);
}
if(is_category_enabled(category::thread_peak_memory{}))
{
rocpd_process_backtrace_metrics_events<category::thread_peak_memory, double>(
0, _ts, m_mem_peak / units::megabyte, _tid);
}
if(is_category_enabled(category::thread_context_switch{}))
{
rocpd_process_backtrace_metrics_events<category::thread_context_switch, int64_t>(
0, _ts, m_ctx_swch, _tid);
}
if(is_category_enabled(category::thread_page_fault{}))
{
rocpd_process_backtrace_metrics_events<category::thread_page_fault, int64_t>(
0, _ts, m_page_flt, _tid);
}
if(is_category_enabled(type_list<hw_counters>{}) &&
is_category_enabled(category::thread_hardware_counter{}))
{
rocpd_process_backtrace_metrics_events<category::thread_hardware_counter,
hw_counter_data_t>(0, _ts, m_hw_counter,
_tid);
}
}
} // namespace component
} // namespace rocprofsys
@@ -83,6 +83,8 @@ struct backtrace_metrics : comp::empty_base
static void configure(bool, int64_t _tid = threading::get_id());
static void init_perfetto(int64_t _tid, valid_array_t);
static void fini_perfetto(int64_t _tid, valid_array_t);
static void init_rocpd(int64_t _tid, valid_array_t);
static void fini_rocpd(int64_t _tid, valid_array_t);
static std::vector<std::string> get_hw_counter_labels(int64_t);
template <typename Tp>
@@ -113,6 +115,7 @@ struct backtrace_metrics : comp::empty_base
const auto& get_hw_counters() const { return m_hw_counter; }
void post_process_perfetto(int64_t _tid, uint64_t _ts) const;
void post_process_rocpd(int64_t _tid, uint64_t _ts) const;
backtrace_metrics& operator-=(const backtrace_metrics&);
@@ -21,15 +21,15 @@
// SOFTWARE.
#include "library/components/comm_data.hpp"
#include "core/agent_manager.hpp"
#include "core/components/fwd.hpp"
#include "core/config.hpp"
#include "core/node_info.hpp"
#include "core/perfetto.hpp"
#include "core/rocpd/data_processor.hpp"
#include "library/tracing.hpp"
#include <timemory/backends/mpi.hpp>
#include <timemory/manager.hpp>
#include <timemory/units.hpp>
#include <timemory/utility/locking.hpp>
namespace rocprofsys
{
@@ -74,6 +74,138 @@ write_perfetto_counter_track(uint64_t _val)
}
} // namespace
namespace
{
rocpd::data_processor&
get_data_processor()
{
return rocpd::data_processor::get_instance();
}
void
rocpd_initialize_comm_data_categories()
{
static bool _is_initialized = false;
if(_is_initialized) return;
get_data_processor().insert_category(category_enum_id<category::comm_data>::value,
trait::name<category::comm_data>::value);
#if defined(ROCPROFSYS_USE_MPI)
get_data_processor().insert_category(category_enum_id<category::mpi>::value,
trait::name<category::mpi>::value);
#endif
#if defined(ROCPROFSYS_USE_RCCL)
get_data_processor().insert_category(category_enum_id<category::rocm_rccl>::value,
trait::name<category::rocm_rccl>::value);
#endif
_is_initialized = true;
}
template <typename Track>
void
rocpd_initialize_track()
{
auto& n_info = node_info::get_instance();
auto thread_id = std::nullopt;
auto _init_track = [&](const char* label) {
ROCPROFSYS_VERBOSE(3, "INSERT_TRACK label: %s, node ID: %d, Process ID: %d",
label, n_info.id, getpid());
get_data_processor().insert_track(label, n_info.id, getpid(), thread_id);
};
static std::once_flag _once{};
std::call_once(_once, _init_track, Track::label);
}
void
rocpd_initialize_comm_data_pmc()
{
[[maybe_unused]] auto& data_processor = get_data_processor();
// find the proper values for a following definitions
[[maybe_unused]] size_t EVENT_CODE = 0;
[[maybe_unused]] size_t INSTANCE_ID = 0;
[[maybe_unused]] constexpr const char* LONG_DESCRIPTION = "";
[[maybe_unused]] constexpr const char* COMPONENT = "";
[[maybe_unused]] constexpr const char* BLOCK = "";
[[maybe_unused]] constexpr const char* EXPRESSION = "";
[[maybe_unused]] constexpr const char* MSG = "bytes";
[[maybe_unused]] constexpr const auto* TARGET_ARCH = "CPU";
auto ni = node_info::get_instance();
constexpr const auto DEVICE_ID = 0; // Assuming CPU device ID is 0
auto& _agent_manager = agent_manager::get_instance();
[[maybe_unused]] auto base_id =
_agent_manager.get_agent_by_id(DEVICE_ID, agent_type::CPU).base_id;
#if defined(ROCPROFSYS_USE_MPI)
data_processor.insert_pmc_description(
ni.id, getpid(), base_id, TARGET_ARCH, EVENT_CODE, INSTANCE_ID,
comm_data::mpi_send::label, "Tracks MPI Send communication data sizes",
trait::name<category::mpi>::description, LONG_DESCRIPTION, COMPONENT, MSG, "ABS",
BLOCK, EXPRESSION, 0, 0);
data_processor.insert_pmc_description(
ni.id, getpid(), base_id, TARGET_ARCH, EVENT_CODE, INSTANCE_ID,
comm_data::mpi_recv::label, "Tracks MPI Receive communication data sizes",
trait::name<category::mpi>::description, LONG_DESCRIPTION, COMPONENT, MSG, "ABS",
BLOCK, EXPRESSION, 0, 0);
#endif
#if defined(ROCPROFSYS_USE_RCCL)
data_processor.insert_pmc_description(
ni.id, getpid(), base_id, TARGET_ARCH, EVENT_CODE, INSTANCE_ID, rccl_send::label,
"Tracks RCCL Send communication data sizes",
trait::name<category::rocm_rccl>::description, LONG_DESCRIPTION, COMPONENT, MSG,
"ABS", BLOCK, EXPRESSION, 0, 0);
data_processor.insert_pmc_description(
ni.id, getpid(), base_id, TARGET_ARCH, EVENT_CODE, INSTANCE_ID, rccl_recv::label,
"Tracks RCCL Receive communication data sizes",
trait::name<category::rocm_rccl>::description, LONG_DESCRIPTION, COMPONENT, MSG,
"ABS", BLOCK, EXPRESSION, 0, 0);
#endif
}
template <typename Track>
void
rocpd_process_cpu_usage_events(const uint32_t device_id, int bytes)
{
auto& data_processor = get_data_processor();
auto event_id = data_processor.insert_event(
category_enum_id<category::comm_data>::value, 0, 0, 0);
auto& agents = agent_manager::get_instance();
auto agent = agents.get_agent_by_id(device_id, agent_type::CPU);
auto insert_event_and_sample = [&](const char* name, uint64_t timestamp,
double value) {
data_processor.insert_pmc_event(event_id, agent.device_id, name, value);
data_processor.insert_sample(name, timestamp, event_id);
};
static std::mutex _mutex{};
static uint64_t value = 0;
uint64_t _now = 0;
{
std::unique_lock<std::mutex> _lk{ _mutex };
_now = rocprofsys::tracing::now<uint64_t>();
bytes = (value += bytes);
}
insert_event_and_sample(Track::label, _now, bytes);
}
} // namespace
void
comm_data::start()
{
if(get_use_rocpd())
{
rocpd_initialize_comm_data_categories();
rocpd_initialize_comm_data_pmc();
}
}
void
comm_data::preinit()
{
@@ -116,13 +248,22 @@ comm_data::audit(const gotcha_data& _data, audit::incoming, const void*, int cou
write_perfetto_counter_track<mpi_send>(count * _size);
if(!rocprofsys::get_use_timemory()) return;
auto _name = std::string_view{ _data.tool_id };
tracker_t _a{ _name };
add(_a, count * _size);
tracker_t _b{ JOIN('/', _name, JOIN('=', "dst", dst)) };
add(_b, count * _size);
add(JOIN('/', _name, JOIN('=', "dst", dst), JOIN('=', "tag", tag)), count * _size);
if(get_use_rocpd())
{
rocpd_initialize_track<mpi_send>();
rocpd_process_cpu_usage_events<mpi_send>(0, count * _size);
}
if(rocprofsys::get_use_timemory())
{
auto _name = std::string_view{ _data.tool_id };
tracker_t _a{ _name };
add(_a, count * _size);
tracker_t _b{ JOIN('/', _name, JOIN('=', "dst", dst)) };
add(_b, count * _size);
add(JOIN('/', _name, JOIN('=', "dst", dst), JOIN('=', "tag", tag)),
count * _size);
}
}
// MPI_Recv
@@ -133,15 +274,24 @@ comm_data::audit(const gotcha_data& _data, audit::incoming, void*, int count,
int _size = mpi_type_size(datatype);
if(_size == 0) return;
write_perfetto_counter_track<mpi_recv>(count * _size);
if(get_use_perfetto()) write_perfetto_counter_track<mpi_recv>(count * _size);
if(!rocprofsys::get_use_timemory()) return;
auto _name = std::string_view{ _data.tool_id };
tracker_t _a{ _name };
add(_a, count * _size);
tracker_t _b{ JOIN('/', _name, JOIN('=', "dst", dst)) };
add(_b, count * _size);
add(JOIN('/', _name, JOIN('=', "dst", dst), JOIN('=', "tag", tag)), count * _size);
if(get_use_rocpd())
{
rocpd_initialize_track<mpi_recv>();
rocpd_process_cpu_usage_events<mpi_recv>(0, count * _size);
}
if(rocprofsys::get_use_timemory())
{
auto _name = std::string_view{ _data.tool_id };
tracker_t _a{ _name };
add(_a, count * _size);
tracker_t _b{ JOIN('/', _name, JOIN('=', "dst", dst)) };
add(_b, count * _size);
add(JOIN('/', _name, JOIN('=', "dst", dst), JOIN('=', "tag", tag)),
count * _size);
}
}
// MPI_Isend
@@ -152,15 +302,24 @@ comm_data::audit(const gotcha_data& _data, audit::incoming, const void*, int cou
int _size = mpi_type_size(datatype);
if(_size == 0) return;
write_perfetto_counter_track<mpi_send>(count * _size);
if(get_use_perfetto()) write_perfetto_counter_track<mpi_send>(count * _size);
if(!rocprofsys::get_use_timemory()) return;
auto _name = std::string_view{ _data.tool_id };
tracker_t _a{ _name };
add(_a, count * _size);
tracker_t _b{ JOIN('/', _name, JOIN('=', "dst", dst)) };
add(_b, count * _size);
add(JOIN('/', _name, JOIN('=', "dst", dst), JOIN('=', "tag", tag)), count * _size);
if(get_use_rocpd())
{
rocpd_initialize_track<mpi_send>();
rocpd_process_cpu_usage_events<mpi_send>(0, count * _size);
}
if(rocprofsys::get_use_timemory())
{
auto _name = std::string_view{ _data.tool_id };
tracker_t _a{ _name };
add(_a, count * _size);
tracker_t _b{ JOIN('/', _name, JOIN('=', "dst", dst)) };
add(_b, count * _size);
add(JOIN('/', _name, JOIN('=', "dst", dst), JOIN('=', "tag", tag)),
count * _size);
}
}
// MPI_Irecv
@@ -171,15 +330,24 @@ comm_data::audit(const gotcha_data& _data, audit::incoming, void*, int count,
int _size = mpi_type_size(datatype);
if(_size == 0) return;
write_perfetto_counter_track<mpi_recv>(count * _size);
if(get_use_perfetto()) write_perfetto_counter_track<mpi_recv>(count * _size);
if(!rocprofsys::get_use_timemory()) return;
auto _name = std::string_view{ _data.tool_id };
tracker_t _a{ _name };
add(_a, count * _size);
tracker_t _b{ JOIN('/', _name, JOIN('=', "dst", dst)) };
add(_b, count * _size);
add(JOIN('/', _name, JOIN('=', "dst", dst), JOIN('=', "tag", tag)), count * _size);
if(get_use_rocpd())
{
rocpd_initialize_track<mpi_recv>();
rocpd_process_cpu_usage_events<mpi_recv>(0, count * _size);
}
if(rocprofsys::get_use_timemory())
{
auto _name = std::string_view{ _data.tool_id };
tracker_t _a{ _name };
add(_a, count * _size);
tracker_t _b{ JOIN('/', _name, JOIN('=', "dst", dst)) };
add(_b, count * _size);
add(JOIN('/', _name, JOIN('=', "dst", dst), JOIN('=', "tag", tag)),
count * _size);
}
}
// MPI_Bcast
@@ -190,13 +358,21 @@ comm_data::audit(const gotcha_data& _data, audit::incoming, void*, int count,
int _size = mpi_type_size(datatype);
if(_size == 0) return;
write_perfetto_counter_track<mpi_send>(count * _size);
if(get_use_perfetto()) write_perfetto_counter_track<mpi_send>(count * _size);
if(!rocprofsys::get_use_timemory()) return;
auto _name = std::string_view{ _data.tool_id };
tracker_t _t{ _name };
add(_t, count * _size);
add(JOIN('/', _name, JOIN('=', "root", root)), count * _size);
if(get_use_rocpd())
{
rocpd_initialize_track<mpi_send>();
rocpd_process_cpu_usage_events<mpi_send>(0, count * _size);
}
if(rocprofsys::get_use_timemory())
{
auto _name = std::string_view{ _data.tool_id };
tracker_t _t{ _name };
add(_t, count * _size);
add(JOIN('/', _name, JOIN('=', "root", root)), count * _size);
}
}
// MPI_Allreduce
@@ -207,11 +383,21 @@ comm_data::audit(const gotcha_data& _data, audit::incoming, const void*, void*,
int _size = mpi_type_size(datatype);
if(_size == 0) return;
write_perfetto_counter_track<mpi_recv>(count * _size);
write_perfetto_counter_track<mpi_send>(count * _size);
if(get_use_perfetto())
{
write_perfetto_counter_track<mpi_recv>(count * _size);
write_perfetto_counter_track<mpi_send>(count * _size);
}
if(!rocprofsys::get_use_timemory()) return;
add(_data, count * _size);
if(get_use_rocpd())
{
rocpd_initialize_track<mpi_send>();
rocpd_initialize_track<mpi_recv>();
rocpd_process_cpu_usage_events<mpi_recv>(0, count * _size);
rocpd_process_cpu_usage_events<mpi_send>(0, count * _size);
}
if(rocprofsys::get_use_timemory()) add(_data, count * _size);
}
// MPI_Sendrecv
@@ -224,30 +410,43 @@ comm_data::audit(const gotcha_data& _data, audit::incoming, const void*, int sen
int _recv_size = mpi_type_size(recvtype);
if(_send_size == 0 || _recv_size == 0) return;
write_perfetto_counter_track<mpi_send>(sendcount * _send_size);
write_perfetto_counter_track<mpi_recv>(recvcount * _recv_size);
if(!rocprofsys::get_use_timemory()) return;
auto _name = std::string_view{ _data.tool_id };
tracker_t _t{ _name };
add(_t, sendcount * _send_size + recvcount * _recv_size);
if(get_use_perfetto())
{
tracker_t _b{ JOIN('/', _name, "send") };
add(_b, sendcount * _send_size);
tracker_t _c{ JOIN('/', _name, JOIN('=', "send", dst)) };
add(_b, sendcount * _send_size);
add(JOIN('/', _name, "send", JOIN('=', "tag", sendtag)), sendcount * _send_size);
add(JOIN('/', _name, JOIN('=', "send", dst), JOIN('=', "tag", sendtag)),
sendcount * _send_size);
write_perfetto_counter_track<mpi_send>(sendcount * _send_size);
write_perfetto_counter_track<mpi_recv>(recvcount * _recv_size);
}
if(get_use_rocpd())
{
tracker_t _b{ JOIN('/', _name, "recv") };
add(_b, recvcount * _recv_size);
tracker_t _c{ JOIN('/', _name, JOIN('=', "recv", src)) };
add(_b, recvcount * _recv_size);
add(JOIN('/', _name, "recv", JOIN('=', "tag", recvtag)), recvcount * _recv_size);
add(JOIN('/', _name, JOIN('=', "recv", src), JOIN('=', "tag", recvtag)),
recvcount * _recv_size);
rocpd_process_cpu_usage_events<mpi_send>(0, sendcount * _send_size);
rocpd_process_cpu_usage_events<mpi_recv>(0, recvcount * _send_size);
}
if(rocprofsys::get_use_timemory())
{
auto _name = std::string_view{ _data.tool_id };
tracker_t _t{ _name };
add(_t, sendcount * _send_size + recvcount * _recv_size);
{
tracker_t _b{ JOIN('/', _name, "send") };
add(_b, sendcount * _send_size);
tracker_t _c{ JOIN('/', _name, JOIN('=', "send", dst)) };
add(_b, sendcount * _send_size);
add(JOIN('/', _name, "send", JOIN('=', "tag", sendtag)),
sendcount * _send_size);
add(JOIN('/', _name, JOIN('=', "send", dst), JOIN('=', "tag", sendtag)),
sendcount * _send_size);
}
{
tracker_t _b{ JOIN('/', _name, "recv") };
add(_b, recvcount * _recv_size);
tracker_t _c{ JOIN('/', _name, JOIN('=', "recv", src)) };
add(_b, recvcount * _recv_size);
add(JOIN('/', _name, "recv", JOIN('=', "tag", recvtag)),
recvcount * _recv_size);
add(JOIN('/', _name, JOIN('=', "recv", src), JOIN('=', "tag", recvtag)),
recvcount * _recv_size);
}
}
}
@@ -262,17 +461,28 @@ comm_data::audit(const gotcha_data& _data, audit::incoming, const void*, int sen
int _recv_size = mpi_type_size(recvtype);
if(_send_size == 0 || _recv_size == 0) return;
write_perfetto_counter_track<mpi_send>(sendcount * _send_size);
write_perfetto_counter_track<mpi_recv>(recvcount * _recv_size);
if(get_use_perfetto())
{
write_perfetto_counter_track<mpi_send>(sendcount * _send_size);
write_perfetto_counter_track<mpi_recv>(recvcount * _recv_size);
}
if(!rocprofsys::get_use_timemory()) return;
auto _name = std::string_view{ _data.tool_id };
tracker_t _t{ _name };
add(_t, sendcount * _send_size + recvcount * _recv_size);
tracker_t _r(JOIN('/', _name, JOIN('=', "root", root)));
add(_r, sendcount * _send_size + recvcount * _recv_size);
add(JOIN('/', _name, JOIN('=', "root", root), "send"), sendcount * _send_size);
add(JOIN('/', _name, JOIN('=', "root", root), "recv"), recvcount * _recv_size);
if(get_use_rocpd())
{
rocpd_process_cpu_usage_events<mpi_send>(0, sendcount * _send_size);
rocpd_process_cpu_usage_events<mpi_recv>(0, recvcount * _send_size);
}
if(rocprofsys::get_use_timemory())
{
auto _name = std::string_view{ _data.tool_id };
tracker_t _t{ _name };
add(_t, sendcount * _send_size + recvcount * _recv_size);
tracker_t _r(JOIN('/', _name, JOIN('=', "root", root)));
add(_r, sendcount * _send_size + recvcount * _recv_size);
add(JOIN('/', _name, JOIN('=', "root", root), "send"), sendcount * _send_size);
add(JOIN('/', _name, JOIN('=', "root", root), "recv"), recvcount * _recv_size);
}
}
// MPI_Alltoall
@@ -285,15 +495,26 @@ comm_data::audit(const gotcha_data& _data, audit::incoming, const void*, int sen
int _recv_size = mpi_type_size(recvtype);
if(_send_size == 0 || _recv_size == 0) return;
write_perfetto_counter_track<mpi_send>(sendcount * _send_size);
write_perfetto_counter_track<mpi_recv>(recvcount * _recv_size);
if(get_use_perfetto())
{
write_perfetto_counter_track<mpi_send>(sendcount * _send_size);
write_perfetto_counter_track<mpi_recv>(recvcount * _recv_size);
}
if(!rocprofsys::get_use_timemory()) return;
auto _name = std::string_view{ _data.tool_id };
tracker_t _t{ _name };
add(_t, sendcount * _send_size + recvcount * _recv_size);
add(JOIN('/', _name, "send"), sendcount * _send_size);
add(JOIN('/', _name, "recv"), recvcount * _recv_size);
if(get_use_rocpd())
{
rocpd_process_cpu_usage_events<mpi_send>(0, sendcount * _send_size);
rocpd_process_cpu_usage_events<mpi_recv>(0, recvcount * _recv_size);
}
if(rocprofsys::get_use_timemory())
{
auto _name = std::string_view{ _data.tool_id };
tracker_t _t{ _name };
add(_t, sendcount * _send_size + recvcount * _recv_size);
add(JOIN('/', _name, "send"), sendcount * _send_size);
add(JOIN('/', _name, "recv"), recvcount * _recv_size);
}
}
#endif
@@ -309,13 +530,17 @@ comm_data::audit(const gotcha_data& _data, audit::incoming, const void*, const v
int _size = rccl_type_size(datatype);
if(_size <= 0) return;
write_perfetto_counter_track<rccl_recv>(count * _size);
if(get_use_perfetto()) write_perfetto_counter_track<rccl_recv>(count * _size);
if(!rocprofsys::get_use_timemory()) return;
auto _name = std::string_view{ _data.tool_id };
tracker_t _t{ _name };
add(_t, count * _size);
add(JOIN('/', _name, JOIN('=', "root", root)), count * _size);
if(get_use_rocpd()) rocpd_process_cpu_usage_events<rccl_recv>(0, count * _size);
if(rocprofsys::get_use_timemory())
{
auto _name = std::string_view{ _data.tool_id };
tracker_t _t{ _name };
add(_t, count * _size);
add(JOIN('/', _name, JOIN('=', "root", root)), count * _size);
}
}
// ncclSend
@@ -334,27 +559,32 @@ comm_data::audit(const gotcha_data& _data, audit::incoming, const void*, size_t
if(_send_types.count(_data.tool_id) > 0)
{
write_perfetto_counter_track<rccl_send>(count * _size);
if(get_use_perfetto()) write_perfetto_counter_track<rccl_send>(count * _size);
if(get_use_rocpd()) rocpd_process_cpu_usage_events<rccl_send>(0, count * _size);
}
else if(_recv_types.count(_data.tool_id) > 0)
{
write_perfetto_counter_track<rccl_recv>(count * _size);
if(get_use_perfetto()) write_perfetto_counter_track<rccl_recv>(count * _size);
if(get_use_rocpd()) rocpd_process_cpu_usage_events<rccl_recv>(0, count * _size);
}
else
{
ROCPROFSYS_CI_THROW(true, "RCCL function not handled: %s", _data.tool_id.c_str());
}
write_perfetto_counter_track<rccl_recv>(count * _size);
if(get_use_perfetto()) write_perfetto_counter_track<rccl_recv>(count * _size);
if(get_use_rocpd()) rocpd_process_cpu_usage_events<rccl_recv>(0, count * _size);
if(!rocprofsys::get_use_timemory()) return;
auto _name = std::string_view{ _data.tool_id };
std::string _label = "root";
if(_name.find("Send") != std::string::npos) _label = "peer";
if(rocprofsys::get_use_timemory())
{
auto _name = std::string_view{ _data.tool_id };
std::string _label = "root";
if(_name.find("Send") != std::string::npos) _label = "peer";
tracker_t _t{ _name };
add(_t, count * _size);
add(JOIN('/', _name, JOIN('=', _label, peer)), count * _size);
tracker_t _t{ _name };
add(_t, count * _size);
add(JOIN('/', _name, JOIN('=', _label, peer)), count * _size);
}
}
// ncclBroadcast
@@ -365,13 +595,16 @@ comm_data::audit(const gotcha_data& _data, audit::incoming, const void*, const v
int _size = rccl_type_size(datatype);
if(_size <= 0) return;
write_perfetto_counter_track<rccl_send>(count * _size);
if(get_use_perfetto()) write_perfetto_counter_track<rccl_send>(count * _size);
if(get_use_rocpd()) rocpd_process_cpu_usage_events<rccl_send>(0, count * _size);
if(!rocprofsys::get_use_timemory()) return;
auto _name = std::string_view{ _data.tool_id };
tracker_t _t{ _name };
add(_t, count * _size);
add(JOIN('/', _data.tool_id, JOIN('=', "root", root)), count * _size);
if(rocprofsys::get_use_timemory())
{
auto _name = std::string_view{ _data.tool_id };
tracker_t _t{ _name };
add(_t, count * _size);
add(JOIN('/', _data.tool_id, JOIN('=', "root", root)), count * _size);
}
}
// ncclAllReduce
@@ -389,19 +622,20 @@ comm_data::audit(const gotcha_data& _data, audit::incoming, const void*, const v
if(_send_types.count(_data.tool_id) > 0)
{
write_perfetto_counter_track<rccl_send>(count * _size);
if(get_use_perfetto()) write_perfetto_counter_track<rccl_send>(count * _size);
if(get_use_rocpd()) rocpd_process_cpu_usage_events<rccl_send>(0, count * _size);
}
else if(_recv_types.count(_data.tool_id) > 0)
{
write_perfetto_counter_track<rccl_recv>(count * _size);
if(get_use_perfetto()) write_perfetto_counter_track<rccl_recv>(count * _size);
if(get_use_rocpd()) rocpd_process_cpu_usage_events<rccl_recv>(0, count * _size);
}
else
{
ROCPROFSYS_CI_THROW(true, "RCCL function not handled: %s", _data.tool_id.c_str());
}
if(!rocprofsys::get_use_timemory()) return;
add(_data, count * _size);
if(rocprofsys::get_use_timemory()) add(_data, count * _size);
}
// ncclAllGather
@@ -413,10 +647,9 @@ comm_data::audit(const gotcha_data& _data, audit::incoming, const void*, const v
int _size = rccl_type_size(datatype);
if(_size <= 0) return;
write_perfetto_counter_track<rccl_recv>(count * _size);
if(!rocprofsys::get_use_timemory()) return;
add(_data, count * _size);
if(get_use_perfetto()) write_perfetto_counter_track<rccl_recv>(count * _size);
if(get_use_rocpd()) rocpd_process_cpu_usage_events<rccl_recv>(0, count * _size);
if(rocprofsys::get_use_timemory()) add(_data, count * _size);
}
#endif
} // namespace component
@@ -82,7 +82,7 @@ struct comm_data : base<comm_data, void>
static void preinit();
static void configure();
static void global_finalize();
static void start() {}
static void start();
static void stop() {}
#if defined(ROCPROFSYS_USE_MPI)
+265 -49
Datei anzeigen
@@ -21,15 +21,15 @@
// SOFTWARE.
#include "library/cpu_freq.hpp"
#include "core/agent.hpp"
#include "core/agent_manager.hpp"
#include "core/common.hpp"
#include "core/components/fwd.hpp"
#include "core/config.hpp"
#include "core/debug.hpp"
#include "core/defines.hpp"
#include "core/node_info.hpp"
#include "core/perfetto.hpp"
#include "core/timemory.hpp"
#include "core/rocpd/data_processor.hpp"
#include "library/components/cpu_freq.hpp"
#include "library/thread_data.hpp"
#include "library/thread_info.hpp"
#include <timemory/components/rusage/backends.hpp>
@@ -44,7 +44,6 @@
#include <sys/resource.h>
#include <tuple>
#include <utility>
#include <vector>
namespace rocprofsys
{
@@ -65,6 +64,181 @@ init_perfetto_counter_tracks(type_list<Types...>)
{
(perfetto_counter_track<Types>::init(), ...);
}
template <typename Category>
inline std::string
get_cpu_freq_track_name(uint64_t cpu_id)
{
return std::string(trait::name<Category>::value) + " [" + std::to_string(cpu_id) +
"]";
}
template <typename Func>
void
do_for_enabled_cpus(Func&& func)
{
const auto& enabled_cpus = component::cpu_freq::get_enabled_cpus();
for(const auto& cpu : enabled_cpus)
{
func(cpu);
}
}
rocpd::data_processor&
get_data_processor()
{
return rocpd::data_processor::get_instance();
}
void
rocpd_initialize_cpu_freq_category()
{
get_data_processor().insert_category(ROCPROFSYS_CATEGORY_CPU_FREQ,
trait::name<category::cpu_freq>::value);
}
void
rocpd_initialize_cpu_freq_tracks()
{
auto& data_processor = get_data_processor();
auto& n_info = node_info::get_instance();
const auto thread_idx = std::nullopt; // Internal thread ID for cpu-freq
do_for_enabled_cpus([&](size_t cpu_id) {
data_processor.insert_track(
get_cpu_freq_track_name<category::cpu_freq>(cpu_id).c_str(), n_info.id,
getpid(), thread_idx);
});
}
void
rocpd_initialize_cpu_usage_tracks()
{
auto& data_processor = get_data_processor();
auto& n_info = node_info::get_instance();
const auto thread_idx = std::nullopt; // Internal thread ID for cpu-freq
data_processor.insert_track(trait::name<category::process_page>::value, n_info.id,
getpid(), thread_idx);
data_processor.insert_track(trait::name<category::process_virt>::value, n_info.id,
getpid(), thread_idx);
data_processor.insert_track(trait::name<category::process_peak>::value, n_info.id,
getpid(), thread_idx);
data_processor.insert_track(trait::name<category::process_context_switch>::value,
n_info.id, getpid(), thread_idx);
data_processor.insert_track(trait::name<category::process_page_fault>::value,
n_info.id, getpid(), thread_idx);
data_processor.insert_track(trait::name<category::process_user_mode_time>::value,
n_info.id, getpid(), thread_idx);
data_processor.insert_track(trait::name<category::process_kernel_mode_time>::value,
n_info.id, getpid(), thread_idx);
}
void
rocpd_initialize_cpu_freq_pmc(size_t dev_id)
{
auto& data_processor = get_data_processor();
// find the proper values for a following definitions
size_t EVENT_CODE = 0;
size_t INSTANCE_ID = 0;
const char* LONG_DESCRIPTION = "";
const char* COMPONENT = "";
const char* BLOCK = "";
const char* EXPRESSION = "";
const char* MEMORY = "MB";
const char* TIME = "sec";
auto ni = node_info::get_instance();
const auto* TARGET_ARCH = "CPU";
auto& _agent_manager = agent_manager::get_instance();
auto base_id = _agent_manager.get_agent_by_id(dev_id, agent_type::CPU).base_id;
do_for_enabled_cpus([&](size_t cpu_id) {
data_processor.insert_pmc_description(
ni.id, getpid(), base_id, TARGET_ARCH, EVENT_CODE, INSTANCE_ID,
get_cpu_freq_track_name<category::cpu_freq>(cpu_id).c_str(), "Frequency",
trait::name<category::cpu_freq>::description, LONG_DESCRIPTION, COMPONENT,
component::cpu_freq::display_unit().c_str(), "ABS", BLOCK, EXPRESSION, 0, 0);
});
data_processor.insert_pmc_description(
ni.id, getpid(), base_id, TARGET_ARCH, EVENT_CODE, INSTANCE_ID,
trait::name<category::process_page>::value, "Memory Usage",
trait::name<category::process_page>::description, LONG_DESCRIPTION, COMPONENT,
MEMORY, "ABS", BLOCK, EXPRESSION, 0, 0);
data_processor.insert_pmc_description(
ni.id, getpid(), base_id, TARGET_ARCH, EVENT_CODE, INSTANCE_ID,
trait::name<category::process_virt>::value, "Virtual Memory Usage",
trait::name<category::process_virt>::description, LONG_DESCRIPTION, COMPONENT,
MEMORY, "ABS", BLOCK, EXPRESSION, 0, 0);
data_processor.insert_pmc_description(
ni.id, getpid(), base_id, TARGET_ARCH, EVENT_CODE, INSTANCE_ID,
trait::name<category::process_peak>::value, "Peak Memory",
trait::name<category::process_peak>::description, LONG_DESCRIPTION, COMPONENT,
MEMORY, "ABS", BLOCK, EXPRESSION, 0, 0);
data_processor.insert_pmc_description(
ni.id, getpid(), base_id, TARGET_ARCH, EVENT_CODE, INSTANCE_ID,
trait::name<category::process_context_switch>::value, "Context Switches",
trait::name<category::process_context_switch>::description, LONG_DESCRIPTION,
COMPONENT, "", "ABS", BLOCK, EXPRESSION, 0, 0);
data_processor.insert_pmc_description(
ni.id, getpid(), base_id, TARGET_ARCH, EVENT_CODE, INSTANCE_ID,
trait::name<category::process_page_fault>::value, "Page Faults",
trait::name<category::process_page_fault>::description, LONG_DESCRIPTION,
COMPONENT, "", "ABS", BLOCK, EXPRESSION, 0, 0);
data_processor.insert_pmc_description(
ni.id, getpid(), base_id, TARGET_ARCH, EVENT_CODE, INSTANCE_ID,
trait::name<category::process_user_mode_time>::value, "User Time",
trait::name<category::process_user_mode_time>::description, LONG_DESCRIPTION,
COMPONENT, TIME, "ABS", BLOCK, EXPRESSION, 0, 0);
data_processor.insert_pmc_description(
ni.id, getpid(), base_id, TARGET_ARCH, EVENT_CODE, INSTANCE_ID,
trait::name<category::process_kernel_mode_time>::value, "Kernel Time",
trait::name<category::process_kernel_mode_time>::description, LONG_DESCRIPTION,
COMPONENT, TIME, "ABS", BLOCK, EXPRESSION, 0, 0);
}
void
rocpd_process_cpu_usage_events(const uint32_t device_id, uint64_t timestamp,
const component::cpu_freq& freq, double mem_page,
double virt_mem_page, double peak_mem,
double context_switch, double page_fault, double user_time,
double kernel_time)
{
auto& data_processor = get_data_processor();
auto event_id = data_processor.insert_event(ROCPROFSYS_CATEGORY_CPU_FREQ, 0, 0, 0);
auto& agent_mngr = agent_manager::get_instance();
auto base_id = agent_mngr.get_agent_by_id(device_id, agent_type::CPU).base_id;
auto insert_event_and_sample = [&](const char* name, double value) {
data_processor.insert_pmc_event(event_id, base_id, name, value);
data_processor.insert_sample(name, timestamp, event_id);
};
do_for_enabled_cpus([&](size_t cpu_id) {
insert_event_and_sample(
get_cpu_freq_track_name<category::cpu_freq>(cpu_id).c_str(), freq.at(cpu_id));
});
insert_event_and_sample(trait::name<category::process_page>::value, mem_page);
insert_event_and_sample(trait::name<category::process_virt>::value, virt_mem_page);
insert_event_and_sample(trait::name<category::process_peak>::value, peak_mem);
insert_event_and_sample(trait::name<category::process_context_switch>::value,
context_switch);
insert_event_and_sample(trait::name<category::process_page_fault>::value, page_fault);
insert_event_and_sample(trait::name<category::process_user_mode_time>::value,
user_time);
insert_event_and_sample(trait::name<category::process_kernel_mode_time>::value,
kernel_time);
}
} // namespace
} // namespace cpu_freq
} // namespace rocprofsys
@@ -76,11 +250,14 @@ namespace cpu_freq
void
setup()
{
init_perfetto_counter_tracks(
type_list<category::cpu_freq, category::process_page, category::process_virt,
category::process_peak, category::process_context_switch,
category::process_page_fault, category::process_user_mode_time,
category::process_kernel_mode_time>{});
if(get_use_perfetto())
{
init_perfetto_counter_tracks(
type_list<category::cpu_freq, category::process_page, category::process_virt,
category::process_peak, category::process_context_switch,
category::process_page_fault, category::process_user_mode_time,
category::process_kernel_mode_time>{});
}
}
void
@@ -163,6 +340,28 @@ post_process()
ROCPROFSYS_VERBOSE(1,
"Post-processing %zu cpu frequency and memory usage entries...\n",
data.size());
auto& enabled_cpus = component::cpu_freq::get_enabled_cpus();
if(get_use_rocpd())
{
rocpd_initialize_cpu_freq_category();
rocpd_initialize_cpu_usage_tracks();
rocpd_initialize_cpu_freq_tracks();
// `get_enabled_cpus()` returns the number of cores enabled for monitoring but the
// actually device_id is 0, since there is a single device available. And the
// agents seems to be assigned per device basis not per core.
// TODO: `get_enabled_cpus()` should be fixed in the future to align with GPU
// implementation.
auto cpu_agents =
agent_manager::get_instance().get_agents_by_type(agent_type::CPU);
for(auto& agent : cpu_agents)
{
rocpd_initialize_cpu_freq_pmc(agent->device_id);
}
}
auto _process_frequencies = [](size_t _idx, size_t _offset) {
using freq_track = perfetto_counter_track<category::cpu_freq>;
@@ -191,14 +390,17 @@ post_process()
};
auto _process_cpu_rusage = []() {
config_perfetto_counter_tracks(
type_list<category::process_page, category::process_virt,
category::process_peak, category::process_context_switch,
category::process_page_fault, category::process_user_mode_time,
category::process_kernel_mode_time>{},
{ "Memory Usage", "Virtual Memory Usage", "Peak Memory", "Context Switches",
"Page Faults", "User Time", "Kernel Time" },
{ "MB", "MB", "MB", "", "", "sec", "sec" });
if(get_use_perfetto())
{
config_perfetto_counter_tracks(
type_list<category::process_page, category::process_virt,
category::process_peak, category::process_context_switch,
category::process_page_fault, category::process_user_mode_time,
category::process_kernel_mode_time>{},
{ "Memory Usage", "Virtual Memory Usage", "Peak Memory",
"Context Switches", "Page Faults", "User Time", "Kernel Time" },
{ "MB", "MB", "MB", "", "", "sec", "sec" });
}
const auto& _thread_info = thread_info::get(0, InternalTID);
ROCPROFSYS_CI_THROW(!_thread_info, "Missing thread info for thread 0");
@@ -209,47 +411,61 @@ post_process()
uint64_t _ts = std::get<0>(itr);
if(!_thread_info->is_valid_time(_ts)) continue;
double _page = std::get<1>(itr);
double _virt = std::get<2>(itr);
double _peak = std::get<3>(itr);
double _page = std::get<1>(itr) / units::megabyte;
double _virt = std::get<2>(itr) / units::megabyte;
double _peak = std::get<3>(itr) / units::megabyte;
uint64_t _cntx = std::get<4>(itr);
uint64_t _flts = std::get<5>(itr);
double _user = std::get<6>(itr);
double _kern = std::get<7>(itr);
write_perfetto_counter_track<category::process_page>(_ts,
_page / units::megabyte);
write_perfetto_counter_track<category::process_virt>(_ts,
_virt / units::megabyte);
write_perfetto_counter_track<category::process_peak>(_ts,
_peak / units::megabyte);
write_perfetto_counter_track<category::process_context_switch>(_ts, _cntx);
write_perfetto_counter_track<category::process_page_fault>(_ts, _flts);
write_perfetto_counter_track<category::process_user_mode_time>(
_ts, _user / units::sec);
write_perfetto_counter_track<category::process_kernel_mode_time>(
_ts, _kern / units::sec);
double _user = std::get<6>(itr) / units::sec;
double _kern = std::get<7>(itr) / units::sec;
if(get_use_perfetto())
{
write_perfetto_counter_track<category::process_page>(_ts, _page);
write_perfetto_counter_track<category::process_virt>(_ts, _virt);
write_perfetto_counter_track<category::process_peak>(_ts, _peak);
write_perfetto_counter_track<category::process_context_switch>(_ts,
_cntx);
write_perfetto_counter_track<category::process_page_fault>(_ts, _flts);
write_perfetto_counter_track<category::process_user_mode_time>(_ts,
_user);
write_perfetto_counter_track<category::process_kernel_mode_time>(_ts,
_kern);
}
if(get_use_rocpd())
{
const auto& freq_data = std::get<8>(itr);
rocpd_process_cpu_usage_events(0, _ts, freq_data, _page, _virt, _peak,
_cntx, _flts, _user, _kern);
}
}
auto _end_ts = _thread_info->get_stop();
write_perfetto_counter_track<category::process_page>(_end_ts, 0.0);
write_perfetto_counter_track<category::process_virt>(_end_ts, 0.0);
write_perfetto_counter_track<category::process_peak>(_end_ts, 0.0);
write_perfetto_counter_track<category::process_context_switch>(_end_ts, 0);
write_perfetto_counter_track<category::process_page_fault>(_end_ts, 0);
write_perfetto_counter_track<category::process_user_mode_time>(_end_ts, 0.0);
write_perfetto_counter_track<category::process_kernel_mode_time>(_end_ts, 0.0);
if(get_use_perfetto())
{
auto _end_ts = _thread_info->get_stop();
write_perfetto_counter_track<category::process_page>(_end_ts, 0.0);
write_perfetto_counter_track<category::process_virt>(_end_ts, 0.0);
write_perfetto_counter_track<category::process_peak>(_end_ts, 0.0);
write_perfetto_counter_track<category::process_context_switch>(_end_ts, 0);
write_perfetto_counter_track<category::process_page_fault>(_end_ts, 0);
write_perfetto_counter_track<category::process_user_mode_time>(_end_ts, 0.0);
write_perfetto_counter_track<category::process_kernel_mode_time>(_end_ts,
0.0);
}
};
_process_cpu_rusage();
auto& enabled_cpu_freqs = component::cpu_freq::get_enabled_cpus();
for(auto itr = enabled_cpu_freqs.begin(); itr != enabled_cpu_freqs.end(); ++itr)
if(get_use_perfetto())
{
auto _idx = *itr;
auto _offset = std::distance(enabled_cpu_freqs.begin(), itr);
_process_frequencies(_idx, _offset);
for(auto itr = enabled_cpus.begin(); itr != enabled_cpus.end(); ++itr)
{
auto _idx = *itr;
auto _offset = std::distance(enabled_cpus.begin(), itr);
_process_frequencies(_idx, _offset);
}
}
enabled_cpu_freqs.clear();
enabled_cpus.clear();
}
} // namespace cpu_freq
} // namespace rocprofsys
@@ -20,14 +20,19 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include <optional>
#define TIMEMORY_KOKKOSP_POSTFIX ROCPROFSYS_PUBLIC_API
#include "api.hpp"
#include "core/agent_manager.hpp"
#include "core/components/fwd.hpp"
#include "core/config.hpp"
#include "core/debug.hpp"
#include "core/defines.hpp"
#include "core/node_info.hpp"
#include "core/perfetto.hpp"
#include "core/rocpd/data_processor.hpp"
#include "core/rocpd/json.hpp"
#include "library/components/category_region.hpp"
#include "library/runtime.hpp"
@@ -150,6 +155,52 @@ violates_name_rules(Arg&& _arg, Args&&... _args)
}
} // namespace
namespace
{
rocprofsys::rocpd::data_processor&
get_data_processor()
{
return rocprofsys::rocpd::data_processor::get_instance();
}
void
rocpd_initialize_kokkos_category()
{
get_data_processor().insert_category(
rocprofsys::category_enum_id<category::kokkos>::value,
rocprofsys::trait::name<category::kokkos>::value);
}
void
rocpd_initialize_kokkos_track()
{
auto& data_processor = get_data_processor();
auto& n_info = rocprofsys::node_info::get_instance();
auto thread_id = std::nullopt;
data_processor.insert_track(rocprofsys::trait::name<category::kokkos>::value,
n_info.id, getpid(), thread_id);
}
void
rocpd_process_kokkos_event(const char* name, const char* event_type, const char* target,
uint64_t timestamp_ns)
{
auto& data_processor = get_data_processor();
auto event_metadata = rocpd::json::create();
event_metadata->set("name", name);
event_metadata->set("event_type", event_type);
event_metadata->set("target", target);
auto event_id = data_processor.insert_event(
rocprofsys::category_enum_id<category::kokkos>::value, 0, 0, 0, "{}", "{}",
event_metadata->to_string().c_str());
data_processor.insert_sample(rocprofsys::trait::name<category::kokkos>::value,
timestamp_ns, event_id, "{}");
}
} // namespace
//--------------------------------------------------------------------------------------//
extern "C"
@@ -256,6 +307,12 @@ extern "C"
rocprofsys_set_mpi_hidden(false, false);
rocprofsys_init_hidden(_mode.c_str(), false, _arg0.c_str());
rocprofsys_push_trace_hidden("kokkos_main");
if(rocprofsys::get_use_rocpd())
{
rocpd_initialize_kokkos_category();
rocpd_initialize_kokkos_track();
}
}
setup_kernel_logger();
@@ -545,6 +602,8 @@ extern "C"
{
if(violates_name_rules(label)) return;
auto timestamp = tim::get_clock_real_now<uint64_t, std::nano>();
ROCPROFSYS_SCOPED_THREAD_STATE(ThreadState::Internal);
if(rocprofsys::config::get_use_perfetto())
{
@@ -559,12 +618,20 @@ extern "C"
"", label, " [dual_view_sync][", (is_device) ? "device" : "host", "]")));
kokkosp::profiler_t<kokkosp_region>{ _name }.mark();
}
if(rocprofsys::config::get_use_rocpd())
{
rocpd_process_kokkos_event(JOIN(" ", _kp_prefix, label).c_str(),
"[dual_view_sync]",
(is_device) ? "device" : "host", timestamp);
}
}
void kokkosp_dual_view_modify(const char* label, const void* const, bool is_device)
{
if(violates_name_rules(label)) return;
auto timestamp = tim::get_clock_real_now<uint64_t, std::nano>();
ROCPROFSYS_SCOPED_THREAD_STATE(ThreadState::Internal);
if(rocprofsys::config::get_use_perfetto())
{
@@ -580,6 +647,13 @@ extern "C"
(is_device) ? "device" : "host", "]")));
kokkosp::profiler_t<kokkosp_region>{ _name }.mark();
}
if(rocprofsys::config::get_use_rocpd())
{
rocpd_process_kokkos_event(JOIN(" ", _kp_prefix, label).c_str(),
"[dual_view_modify]",
(is_device) ? "device" : "host", timestamp);
}
}
//----------------------------------------------------------------------------------//
@@ -21,26 +21,10 @@
// SOFTWARE.
#include "library/rocprofiler-sdk/counters.hpp"
#include "common/synchronized.hpp"
#include "core/debug.hpp"
#include "core/timemory.hpp"
#include "library/rocprofiler-sdk/fwd.hpp"
#include <timemory/utility/types.hpp>
#include <rocprofiler-sdk/agent.h>
#include <rocprofiler-sdk/buffer_tracing.h>
#include <rocprofiler-sdk/callback_tracing.h>
#include <rocprofiler-sdk/cxx/hash.hpp>
#include <rocprofiler-sdk/cxx/name_info.hpp>
#include <rocprofiler-sdk/cxx/operators.hpp>
#include <rocprofiler-sdk/dispatch_counting_service.h>
#include <rocprofiler-sdk/fwd.h>
#include <rocprofiler-sdk/registration.h>
#include <memory>
#include <unordered_map>
#include <vector>
#include <timemory/utility/types.hpp>
namespace rocprofsys
{
+334 -13
Datei anzeigen
@@ -26,7 +26,10 @@
#include "core/config.hpp"
#include "core/debug.hpp"
#include "core/locking.hpp"
#include "core/node_info.hpp"
#include "core/perf.hpp"
#include "core/rocpd/data_processor.hpp"
#include "core/rocpd/json.hpp"
#include "core/state.hpp"
#include "core/utility.hpp"
#include "library/components/backtrace.hpp"
@@ -153,6 +156,136 @@ namespace
{
using sampler_allocator_t = typename sampler_t::allocator_t;
template <typename Category>
inline std::string
get_category_track_name(uint64_t tid)
{
return std::string(trait::name<Category>::value) + "_" + std::to_string(tid);
}
std::string
generate_call_stack_json(const tim::unwind::processed_entry& stack_entry)
{
auto call_stack = ::rocpd::json::create();
call_stack->set("name", std::string(demangle(stack_entry.name)));
call_stack->set("pc", as_hex(stack_entry.address));
call_stack->set("file", std::string(stack_entry.location));
return call_stack->to_string();
}
std::string
generate_line_info_json(const tim::unwind::processed_entry& line_info_entry)
{
auto line_info = ::rocpd::json::create();
line_info->set("line_address", as_hex(line_info_entry.line_address));
line_info->set("name", std::string(demangle(line_info_entry.name)));
if(line_info_entry.lineinfo && !line_info_entry.lineinfo.lines.empty())
{
auto _lines = line_info_entry.lineinfo.lines;
std::reverse(_lines.begin(), _lines.end());
for(const auto& line : _lines)
{
auto inlined = ::rocpd::json::create();
inlined->set("name", std::string(demangle(line.name)));
inlined->set("location", std::string(line.location));
inlined->set("line", std::to_string(line.line));
line_info->set("inlined", inlined);
}
}
return line_info->to_string();
}
std::string
generate_hw_counter_json(int64_t _tid, const backtrace_metrics& metrics)
{
auto extdata = ::rocpd::json::create();
if(!metrics.get_hw_counters().empty())
{
auto _labels = backtrace_metrics::get_hw_counter_labels(_tid);
auto _hw_cnt_vals = metrics.get_hw_counters();
auto hw_counters = ::rocpd::json::create();
for(size_t i = 0; i < _labels.size(); ++i)
{
hw_counters->set(_labels.at(i), _hw_cnt_vals.at(i));
}
extdata->set("hw_counters", hw_counters);
}
return extdata->to_string();
}
rocpd::data_processor&
get_data_processor()
{
return rocpd::data_processor::get_instance();
}
void
rocpd_initialize_sampling_category()
{
static bool _is_initialized = false;
if(_is_initialized) return;
auto& data_processor = get_data_processor();
data_processor.insert_category(ROCPROFSYS_CATEGORY_SAMPLING,
trait::name<category::sampling>::value);
data_processor.insert_category(ROCPROFSYS_CATEGORY_OVERFLOW_SAMPLING,
trait::name<category::overflow_sampling>::value);
data_processor.insert_category(ROCPROFSYS_CATEGORY_TIMER_SAMPLING,
trait::name<category::timer_sampling>::value);
_is_initialized = true;
}
size_t
rocpd_initialize_thread_info(size_t tid)
{
const auto& _thread_info = thread_info::get(tid, SequentTID);
ROCPROFSYS_CI_THROW(!_thread_info, "No valid thread info for tid=%li\n", tid);
if(!_thread_info) return -1;
auto& data_processor = get_data_processor();
auto& n_info = node_info::get_instance();
return data_processor.insert_thread_info(
n_info.id, getppid(), getpid(), _thread_info->index_data->system_value,
threading::get_thread_name().c_str(), _thread_info->get_start(),
_thread_info->get_stop(), "{}");
}
void
rocpd_init_track(const char* track_name, int64_t tid)
{
auto& data_processor = get_data_processor();
auto& n_info = node_info::get_instance();
data_processor.insert_track(track_name, n_info.id, getpid(), tid, "{}");
}
template <typename Category>
void
rocpd_insert_region(size_t thread_id, size_t start_time, size_t end_time, size_t name_id,
const char* track, const char* call_stack = "{}",
const char* line_info = "{}", const char* extdata = "{}")
{
auto& data_processor = get_data_processor();
auto& n_info = node_info::get_instance();
auto event_id = data_processor.insert_event(category_enum_id<Category>::value, 0, 0,
0, call_stack, line_info, extdata);
data_processor.insert_region(n_info.id, getpid(), thread_id, start_time, end_time,
name_id, event_id);
data_processor.insert_sample(track, start_time, event_id);
}
auto&
get_sampler_allocators()
{
@@ -810,6 +943,10 @@ void
post_process_timemory(int64_t, const std::vector<timer_sampling_data>&,
const std::vector<overflow_sampling_data>&);
void
post_process_rocpd(int64_t _tid, const std::vector<timer_sampling_data>& _timer_data,
const std::vector<overflow_sampling_data>& _overflow_data);
auto static_strings = std::set<std::string>{};
} // namespace
@@ -939,15 +1076,15 @@ post_process()
auto _raw_data = _sampler->get_data();
auto _loaded_data = load_offload_buffer(i);
for(auto litr : _loaded_data)
for(auto line : _loaded_data)
{
while(!litr.is_empty())
while(!line.is_empty())
{
auto _v = sampler_bundle_t{};
litr.read(&_v);
line.read(&_v);
_raw_data.emplace_back(std::move(_v));
}
litr.destroy();
line.destroy();
}
ROCPROFSYS_VERBOSE(2 || get_debug_sampling(),
@@ -988,6 +1125,7 @@ post_process()
if(get_use_perfetto()) post_process_perfetto(i, _timer_data, _overflow_data);
if(get_use_timemory()) post_process_timemory(i, _timer_data, _overflow_data);
if(get_use_rocpd()) post_process_rocpd(i, _timer_data, _overflow_data);
}
else
{
@@ -1205,13 +1343,13 @@ post_process_perfetto(int64_t _tid, const std::vector<timer_sampling_data>& _tim
auto _lines = iitr.lineinfo.lines;
std::reverse(_lines.begin(), _lines.end());
size_t _n = 0;
for(const auto& litr : _lines)
for(const auto& line : _lines)
{
auto _label = JOIN('-', "lineinfo", _n++);
tracing::add_perfetto_annotation(
ctx, _label.c_str(),
JOIN('@', demangle(litr.name),
JOIN(':', litr.location, litr.line)));
JOIN('@', demangle(line.name),
JOIN(':', line.location, line.line)));
}
}
}
@@ -1298,11 +1436,11 @@ post_process_perfetto(int64_t _tid, const std::vector<timer_sampling_data>& _tim
auto _lines = iitr.lineinfo.lines;
std::reverse(_lines.begin(), _lines.end());
size_t _n = 0;
for(const auto& litr : _lines)
for(const auto& line : _lines)
{
const auto* _name =
static_strings.emplace(demangle(litr.name)).first->c_str();
auto _info = JOIN(':', litr.location, litr.line);
static_strings.emplace(demangle(line.name)).first->c_str();
auto _info = JOIN(':', line.location, line.line);
tracing::push_perfetto_track(
category::timer_sampling{}, _name, _track, _beg,
[&](::perfetto::EventContext ctx) {
@@ -1342,13 +1480,13 @@ post_process_perfetto(int64_t _tid, const std::vector<timer_sampling_data>& _tim
auto _lines = iitr.lineinfo.lines;
std::reverse(_lines.begin(), _lines.end());
size_t _n = 0;
for(const auto& litr : _lines)
for(const auto& line : _lines)
{
auto _label = JOIN('-', "lineinfo", _n++);
tracing::add_perfetto_annotation(
ctx, _label.c_str(),
JOIN('@', demangle(litr.name),
JOIN(':', litr.location, litr.line)));
JOIN('@', demangle(line.name),
JOIN(':', line.location, line.line)));
}
}
}
@@ -1540,6 +1678,189 @@ post_process_timemory(int64_t _tid, const std::vector<timer_sampling_data>& _tim
}
}
void
rocpd_post_process_overflow_data(
int64_t _tid, const std::vector<overflow_sampling_data>& _overflow_data)
{
auto& data_processor = get_data_processor();
const auto& _thread_info = thread_info::get(_tid, SequentTID);
ROCPROFSYS_CI_THROW(!_thread_info, "No valid thread info for tid=%li\n", _tid);
if(!_thread_info) return;
auto _overflow_event =
get_setting_value<std::string>("ROCPROFSYS_SAMPLING_OVERFLOW_EVENT").value_or("");
if(!_overflow_event.empty() && !_overflow_data.empty())
{
auto _beg_ns = std::max(_overflow_data.front().m_beg, _thread_info->get_start());
auto _end_ns = std::min(_overflow_data.back().m_end, _thread_info->get_stop());
const auto _overflow_prefix = std::string_view{ "PERF_COUNT_" };
const auto _overflow_pos = _overflow_event.find(_overflow_prefix);
if(_overflow_pos != std::string::npos)
_overflow_event =
_overflow_event.substr(_overflow_pos + _overflow_prefix.length());
const auto* _main_name =
static_strings.emplace(join(" ", _overflow_event, "samples [rocprof-sys]"))
.first->c_str();
auto main_name_id = data_processor.insert_string(_main_name);
const auto& _track_name =
JOIN(" ", "Thread", _thread_info->index_data->sequent_value, "Overflow",
"(S)", _thread_info->index_data->system_value);
auto thread_idx = rocpd_initialize_thread_info(_tid);
rocpd_init_track(_track_name.c_str(), thread_idx);
rocpd_insert_region<category::overflow_sampling>(
thread_idx, _beg_ns, _end_ns, main_name_id, _track_name.c_str());
for(const auto& itr : _overflow_data)
{
auto _beg = itr.m_beg;
auto _end = itr.m_end;
if(!_thread_info->is_valid_lifetime({ _beg, _end })) continue;
for(const auto& iitr : itr.m_stack)
{
const auto* _name =
static_strings.emplace(demangle(iitr.name)).first->c_str();
auto name_id = data_processor.insert_string(_name);
rocpd_insert_region<category::overflow_sampling>(
thread_idx, _beg, _end, name_id, _track_name.c_str(),
generate_call_stack_json(iitr).c_str(),
generate_line_info_json(iitr).c_str());
}
}
}
}
void
rocpd_post_process_backtrace_metrics(int64_t _tid,
const std::vector<timer_sampling_data>& _timer_data)
{
auto _valid_metrics = backtrace_metrics::valid_array_t{};
for(const auto& itr : _timer_data)
{
_valid_metrics |= itr.m_metrics.get_valid();
}
if(trait::runtime_enabled<backtrace_metrics>::get() && get_use_rocpd())
{
ROCPROFSYS_VERBOSE(3 || get_debug_sampling(),
"[%li] Post-processing metrics for rocpd...\n", _tid);
backtrace_metrics::init_rocpd(_tid, _valid_metrics);
for(const auto& itr : _timer_data)
itr.m_metrics.post_process_rocpd(_tid, 0.5 * (itr.m_beg + itr.m_end));
backtrace_metrics::fini_rocpd(_tid, _valid_metrics);
}
}
void
rocpd_post_process_timer_data(int64_t _tid,
const std::vector<timer_sampling_data>& _timer_data)
{
auto& data_processor = get_data_processor();
const auto& _thread_info = thread_info::get(_tid, SequentTID);
ROCPROFSYS_CI_THROW(!_thread_info, "No valid thread info for tid=%li\n", _tid);
if(!_thread_info) return;
if(!_timer_data.empty())
{
rocpd_post_process_backtrace_metrics(_tid, _timer_data);
auto _beg_ns = std::max(_timer_data.front().m_beg, _thread_info->get_start());
auto _end_ns = std::min(_timer_data.back().m_end, _thread_info->get_stop());
const auto _track_name =
JOIN(" ", "Thread", _thread_info->index_data->sequent_value, "(S)",
_thread_info->index_data->system_value);
auto thread_idx = rocpd_initialize_thread_info(_tid);
rocpd_init_track(_track_name.c_str(), thread_idx);
const auto main_name_id = data_processor.insert_string("samples [rocprof-sys]");
rocpd_insert_region<category::timer_sampling>(thread_idx, _beg_ns, _end_ns,
main_name_id, _track_name.c_str());
auto _labels = backtrace_metrics::get_hw_counter_labels(_tid);
for(const auto& itr : _timer_data)
{
size_t _ncount = 0;
uint64_t _beg = itr.m_beg;
uint64_t _end = itr.m_end;
if(!_thread_info->is_valid_lifetime({ _beg, _end })) continue;
for(const auto& iitr : itr.m_stack)
{
auto _ncur = _ncount++;
// the begin/end + HW counters will be same for entire call-stack so only
// annotate the top and the bottom functons to keep the data consumption
// low
bool _include_common = (_ncur == 0 || _ncur + 1 == itr.m_stack.size());
// Only annotate HW counters when first or last and HW counters are not
// empty
bool _include_hw =
_include_common && !itr.m_metrics.get_hw_counters().empty();
std::string hw_counter_json = "{}";
if(_include_hw)
{
// current values when read
hw_counter_json = generate_hw_counter_json(_tid, itr.m_metrics);
}
if(get_sampling_include_inlines() && iitr.lineinfo)
{
auto _lines = iitr.lineinfo.lines;
std::reverse(_lines.begin(), _lines.end());
size_t _n = 0;
for(const auto& line : _lines)
{
const auto* _name =
static_strings.emplace(demangle(line.name)).first->c_str();
auto inlined_name_id = data_processor.insert_string(_name);
auto inlined_call_stack = ::rocpd::json::create();
inlined_call_stack->set("name", std::string(demangle(line.name)));
inlined_call_stack->set("location", std::string(line.location));
inlined_call_stack->set("line", std::to_string(line.line));
inlined_call_stack->set("inlined", "true");
rocpd_insert_region<category::timer_sampling>(
thread_idx, _beg, _end, inlined_name_id, _track_name.c_str(),
inlined_call_stack->to_string().c_str(), "{}",
// Only include HW counters for first inlined function
(_n == 0) ? hw_counter_json.c_str() : "{}");
}
}
else
{
const auto* _name = static_strings.emplace(iitr.name).first->c_str();
const auto name_id = data_processor.insert_string(_name);
rocpd_insert_region<category::timer_sampling>(
thread_idx, _beg, _end, name_id, _track_name.c_str(),
generate_call_stack_json(iitr).c_str(),
generate_line_info_json(iitr).c_str(), hw_counter_json.c_str());
}
}
}
}
}
void
post_process_rocpd(int64_t _tid, const std::vector<timer_sampling_data>& _timer_data,
const std::vector<overflow_sampling_data>& _overflow_data)
{
rocpd_initialize_sampling_category();
rocpd_post_process_overflow_data(_tid, _overflow_data);
rocpd_post_process_timer_data(_tid, _timer_data);
}
struct sampling_initialization
{
static void preinit()