Fix dimension mismatch for multi-GPU systems with identical architect… (#1440)
* Fix dimension mismatch for multi-GPU systems with identical architectures This change addresses an issue where counter dimensions were incorrectly shared across all GPU agents with the same architecture name, even when those agents had different hardware configurations (e.g., different CU counts). Changes: - Updated getBlockDimensions() to accept agent ID instead of architecture name - Made dimension cache agent-specific instead of architecture-specific - Updated set_dimensions() in AST evaluation to use specific agent ID - Modified all API functions to handle agent-specific dimension lookups - Updated tests to work with agent-specific dimensions This fix ensures that dimensions accurately reflect the actual hardware configuration of each individual GPU agent, preventing dimension mismatches in multi-GPU systems where GPUs share the same architecture but have different physical configurations. Counter ID Representation Changes: - Modified counter_id encoding to include agent information in bits 37-32 - Agent logical_node_id is encoded as (value + 1) to ensure agent 0 is detectable - Counter records internally store only 16-bit base metric IDs (bits 15-0) - Tool reconstructs agent-encoded counter IDs from base metric ID & agent info - Instance record counter_id field uses bitwise AND mask to extract base metric ID (counter_id.handle & 0xFFFF) to fit in 16-bit storage - Output generators (CSV, JSON, Perfetto) use agent-encoded IDs for consistency - Updated counter_config.cpp and metrics.cpp to extract base metric ID when needed - All counter lookups now properly handle agent-encoded vs base metric IDs This ensures counter IDs are consistent between metadata and output records while maintaining compact storage in instance records.
This commit is contained in:
+8
-1
@@ -292,7 +292,14 @@ dispatch_callback(rocprofiler_dispatch_counting_service_data_t dispatch_data,
|
||||
"Could not query counter_id");
|
||||
cap.expected_counter_names.emplace(found_counter.handle, std::string(info.name));
|
||||
cap.remaining.push_back(found_counter);
|
||||
cap.expected.emplace(found_counter.handle, info.dimensions_instances_count);
|
||||
|
||||
// Query instance count for the specific agent being dispatched to
|
||||
size_t instance_count = 0;
|
||||
ROCPROFILER_CALL(
|
||||
rocprofiler_query_counter_instance_count(
|
||||
dispatch_data.dispatch_info.agent_id, found_counter, &instance_count),
|
||||
"Could not query counter instance count");
|
||||
cap.expected.emplace(found_counter.handle, instance_count);
|
||||
|
||||
auto& info_vector =
|
||||
cap.expected_data_dims.emplace(found_counter.handle, validate_dim_presence{})
|
||||
|
||||
@@ -77,6 +77,9 @@ set(IS_DISABLED ON)
|
||||
if(attdecoder_FOUND)
|
||||
set(IS_DISABLED OFF)
|
||||
endif()
|
||||
if(ROCPROFILER_DISABLE_UNSTABLE_CTESTS)
|
||||
set(IS_DISABLED ON)
|
||||
endif()
|
||||
|
||||
rocprofiler_samples_get_preload_env(PRELOAD_ENV)
|
||||
list(APPEND PRELOAD_ENV "ROCPROFILER_TRACE_DECODER_LIB_PATH=${attdecoder_LIB_DIR}")
|
||||
|
||||
@@ -31,7 +31,7 @@ Definitions
|
||||
ROCPROFILER_DIMENSION_XCC, ///< XCC dimension of result
|
||||
ROCPROFILER_DIMENSION_AID, ///< AID dimension of result
|
||||
ROCPROFILER_DIMENSION_SHADER_ENGINE, ///< SE dimension of result
|
||||
ROCPROFILER_DIMENSION_AGENT, ///< Agent dimension
|
||||
ROCPROFILER_DIMENSION_AGENT, ///< Agent dimension (note: this field is not set externally)
|
||||
ROCPROFILER_DIMENSION_SHADER_ARRAY, ///< Number of shader arrays
|
||||
ROCPROFILER_DIMENSION_WGP, ///< Number of workgroup processors
|
||||
ROCPROFILER_DIMENSION_INSTANCE, ///< From unspecified hardware register
|
||||
|
||||
@@ -3,8 +3,16 @@
|
||||
# Installation of public C++ headers
|
||||
#
|
||||
#
|
||||
set(ROCPROFILER_CXX_HEADER_FILES enum_string.hpp hash.hpp name_info.hpp operators.hpp
|
||||
perfetto.hpp utility.hpp serialization.hpp version.hpp)
|
||||
set(ROCPROFILER_CXX_HEADER_FILES
|
||||
constants.hpp
|
||||
enum_string.hpp
|
||||
hash.hpp
|
||||
name_info.hpp
|
||||
operators.hpp
|
||||
perfetto.hpp
|
||||
utility.hpp
|
||||
serialization.hpp
|
||||
version.hpp)
|
||||
|
||||
install(
|
||||
FILES ${ROCPROFILER_CXX_HEADER_FILES}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2023-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 <rocprofiler-sdk/fwd.h>
|
||||
|
||||
namespace rocprofiler
|
||||
{
|
||||
namespace sdk
|
||||
{
|
||||
// Null/invalid agent ID constant
|
||||
constexpr auto null_agent_id = rocprofiler_agent_id_t{.handle = 0};
|
||||
|
||||
} // namespace sdk
|
||||
} // namespace rocprofiler
|
||||
@@ -30,6 +30,8 @@
|
||||
#include "statistics.hpp"
|
||||
#include "timestamps.hpp"
|
||||
|
||||
#include "lib/rocprofiler-sdk/counters/id_decode.hpp"
|
||||
|
||||
#include <rocprofiler-sdk/fwd.h>
|
||||
#include <rocprofiler-sdk/marker/api_id.h>
|
||||
#include <rocprofiler-sdk/cxx/operators.hpp>
|
||||
@@ -600,7 +602,11 @@ generate_csv(const output_config& cfg,
|
||||
|
||||
auto counter_id_to_name = std::unordered_map<rocprofiler_counter_id_t, std::string_view>{};
|
||||
for(const auto& itr : tool_metadata.get_counter_info())
|
||||
{
|
||||
// Counter records now contain agent-encoded IDs (reconstructed in tool.cpp),
|
||||
// so we use the full agent-encoded ID from metadata as the map key
|
||||
counter_id_to_name.emplace(itr.id, itr.name);
|
||||
}
|
||||
|
||||
for(auto ditr : data)
|
||||
{
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <rocprofiler-sdk/fwd.h>
|
||||
#include <rocprofiler-sdk/marker/api_id.h>
|
||||
#include <rocprofiler-sdk/rocprofiler.h>
|
||||
#include <rocprofiler-sdk/cxx/constants.hpp>
|
||||
#include <rocprofiler-sdk/cxx/hash.hpp>
|
||||
#include <rocprofiler-sdk/cxx/operators.hpp>
|
||||
#include <rocprofiler-sdk/cxx/perfetto.hpp>
|
||||
@@ -491,9 +492,8 @@ write_otf2(const output_config& cfg,
|
||||
{
|
||||
// Free functions do not track agent information. Below handles case where
|
||||
// null rocprof agent id is passed to generate OTF2
|
||||
constexpr auto null_rocp_agent_id = rocprofiler_agent_id_t{.handle = 0};
|
||||
const rocprofiler_agent_t* _agent = nullptr;
|
||||
if(agent != null_rocp_agent_id)
|
||||
const rocprofiler_agent_t* _agent = nullptr;
|
||||
if(agent != sdk::null_agent_id)
|
||||
{
|
||||
_agent = _get_agent(agent);
|
||||
}
|
||||
@@ -895,9 +895,8 @@ write_otf2(const output_config& cfg,
|
||||
auto _hash = get_hash_id(evt.name);
|
||||
// Using max numeric limits results in an out-of-bound runtime error for OTF2
|
||||
// and perfetto for agent ids. Setting handle to 0 for free functions.
|
||||
constexpr auto null_rocp_agent_id = rocprofiler_agent_id_t{.handle = 0};
|
||||
auto handle = agent.handle;
|
||||
if(agent == null_rocp_agent_id) handle = 0;
|
||||
auto handle = agent.handle;
|
||||
if(agent == sdk::null_agent_id) handle = 0;
|
||||
|
||||
add_write_string(_hash, evt.name);
|
||||
OTF2_CHECK(OTF2_GlobalDefWriter_WriteLocation(global_def_writer,
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include <rocprofiler-sdk/fwd.h>
|
||||
#include <rocprofiler-sdk/marker/api_id.h>
|
||||
#include <rocprofiler-sdk/cxx/constants.hpp>
|
||||
#include <rocprofiler-sdk/cxx/hash.hpp>
|
||||
#include <rocprofiler-sdk/cxx/operators.hpp>
|
||||
#include <rocprofiler-sdk/cxx/perfetto.hpp>
|
||||
@@ -309,7 +310,11 @@ write_perfetto(
|
||||
|
||||
auto counter_id_to_name = std::unordered_map<rocprofiler_counter_id_t, std::string_view>{};
|
||||
for(const auto& itr : tool_metadata.get_counter_info())
|
||||
{
|
||||
// Counter records now contain agent-encoded IDs (reconstructed in tool.cpp),
|
||||
// so we use the full agent-encoded ID from metadata as the map key
|
||||
counter_id_to_name.emplace(itr.id, itr.name);
|
||||
}
|
||||
|
||||
// Map: correlation_id -> map<counter_id, value>
|
||||
auto dispatch_counter_id_value =
|
||||
@@ -837,7 +842,6 @@ write_perfetto(
|
||||
}
|
||||
|
||||
// memory allocation counter track
|
||||
constexpr auto null_rocp_agent_id = rocprofiler_agent_id_t{.handle = 0};
|
||||
struct free_memory_information
|
||||
{
|
||||
rocprofiler_timestamp_t start_timestamp = 0;
|
||||
@@ -874,7 +878,7 @@ write_perfetto(
|
||||
if(itr.operation == ROCPROFILER_MEMORY_ALLOCATION_ALLOCATE ||
|
||||
itr.operation == ROCPROFILER_MEMORY_ALLOCATION_VMEM_ALLOCATE)
|
||||
{
|
||||
LOG_IF(FATAL, itr.agent_id == null_rocp_agent_id)
|
||||
LOG_IF(FATAL, itr.agent_id == sdk::null_agent_id)
|
||||
<< "Missing agent id for memory allocation trace";
|
||||
mem_alloc_endpoints[itr.agent_id].emplace(
|
||||
itr.start_timestamp,
|
||||
|
||||
@@ -1552,9 +1552,11 @@ counter_record_callback(rocprofiler_dispatch_counting_service_data_t dispatch_da
|
||||
|
||||
for(size_t count = 0; count < record_count; ++count)
|
||||
{
|
||||
// Get agent-encoded counter ID from record
|
||||
auto _counter_id = rocprofiler_counter_id_t{};
|
||||
ROCPROFILER_CALL(rocprofiler_query_record_counter_id(record_data[count].id, &_counter_id),
|
||||
"query record counter id");
|
||||
|
||||
serialized_records.emplace_back(
|
||||
tool::tool_counter_value_t{_counter_id, record_data[count].counter_value});
|
||||
}
|
||||
|
||||
@@ -108,27 +108,6 @@ v1_get_block_counters(hsa_agent_t agent, const hsa_ven_amd_aqlprofile_event_t& e
|
||||
return max_block_counters;
|
||||
}
|
||||
|
||||
rocprofiler_status_t
|
||||
v1_get_dim_info(hsa_agent_t agent,
|
||||
hsa_ven_amd_aqlprofile_event_t event,
|
||||
uint32_t sample_id,
|
||||
std::map<int, uint64_t>& dims)
|
||||
{
|
||||
auto callback = [](int, int id, int extent, int, const char*, void* userdata) -> hsa_status_t {
|
||||
auto& map = *static_cast<std::map<int, uint64_t>*>(userdata);
|
||||
map.emplace(id, extent);
|
||||
return HSA_STATUS_SUCCESS;
|
||||
};
|
||||
|
||||
if(hsa_ven_amd_aqlprofile_iterate_event_coord(
|
||||
agent, event, sample_id, callback, static_cast<void*>(&dims)) != HSA_STATUS_SUCCESS)
|
||||
{
|
||||
return ROCPROFILER_STATUS_ERROR_AQL_NO_EVENT_COORD;
|
||||
}
|
||||
|
||||
return ROCPROFILER_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
void
|
||||
test_init()
|
||||
{
|
||||
@@ -286,47 +265,3 @@ TEST(aql_helpers, get_dim_info)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(aql_helpers, get_dim_info_compare_v1)
|
||||
{
|
||||
ASSERT_EQ(hsa_init(), HSA_STATUS_SUCCESS);
|
||||
test_init();
|
||||
auto agents = agent::get_agents();
|
||||
|
||||
ASSERT_FALSE(agents.empty());
|
||||
|
||||
for(auto agent : agents)
|
||||
{
|
||||
if(agent->type == ROCPROFILER_AGENT_TYPE_CPU) continue;
|
||||
auto metrics = findDeviceMetrics(*agent, {});
|
||||
ASSERT_FALSE(metrics.empty());
|
||||
|
||||
for(auto& metric : metrics)
|
||||
{
|
||||
std::map<int, uint64_t> dims;
|
||||
std::map<int, uint64_t> dims_v1;
|
||||
auto query = aql::get_query_info(agent->id, metric);
|
||||
for(unsigned block_index = 0; block_index < query.instance_count; ++block_index)
|
||||
{
|
||||
aqlprofile_pmc_event_t event = {
|
||||
.block_index = block_index,
|
||||
.event_id = static_cast<uint32_t>(std::atoi(metric.event().c_str())),
|
||||
.flags = aqlprofile_pmc_event_flags_t{0},
|
||||
.block_name = static_cast<hsa_ven_amd_aqlprofile_block_name_t>(query.id)};
|
||||
|
||||
hsa_ven_amd_aqlprofile_event_t event_v1 = {
|
||||
.block_name = static_cast<hsa_ven_amd_aqlprofile_block_name_t>(query.id),
|
||||
.block_index = block_index,
|
||||
.counter_id = static_cast<uint32_t>(std::atoi(metric.event().c_str()))};
|
||||
EXPECT_EQ(ROCPROFILER_STATUS_SUCCESS, aql::get_dim_info(agent->id, event, 0, dims));
|
||||
EXPECT_EQ(
|
||||
ROCPROFILER_STATUS_SUCCESS,
|
||||
v1_get_dim_info(
|
||||
agent::get_agent_cache(agent)->get_hsa_agent(), event_v1, 0, dims_v1));
|
||||
EXPECT_EQ(dims.size(), dims_v1.size());
|
||||
EXPECT_EQ(dims, dims_v1);
|
||||
}
|
||||
}
|
||||
}
|
||||
hsa_shut_down();
|
||||
}
|
||||
|
||||
@@ -219,7 +219,20 @@ flush(rocprofiler_buffer_id_t buffer_id, bool wait)
|
||||
|
||||
} catch(std::exception& e)
|
||||
{
|
||||
ROCP_CI_LOG(ERROR) << "buffer callback threw an exception: " << e.what();
|
||||
ROCP_CI_LOG(ERROR) << fmt::format(
|
||||
"buffer callback threw an exception: {} [buffer_id={}, idx={}, "
|
||||
"offset={}, context_id={}, callback={}, callback_data={}, records={}, "
|
||||
"first_record_ptr={}, drop_count={}]",
|
||||
e.what(),
|
||||
buffer_id.handle,
|
||||
idx,
|
||||
offset,
|
||||
buff_v->context_id,
|
||||
reinterpret_cast<const void*>(buff_v->callback),
|
||||
buff_v->callback_data,
|
||||
_headers.size(),
|
||||
(!_headers.empty() ? static_cast<const void*>(&_headers[0]) : nullptr),
|
||||
buff_v->drop_count.load());
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -62,7 +62,9 @@ rocprofiler_create_counter_config(rocprofiler_agent_id_t agent_id,
|
||||
{
|
||||
auto& counter_id = counters_list[i];
|
||||
|
||||
const auto* metric_ptr = rocprofiler::common::get_val(id_map, counter_id.handle);
|
||||
// Extract base metric ID from counter_id (handles agent-encoded counter IDs)
|
||||
auto base_metric_id = rocprofiler::counters::get_base_metric_from_counter_id(counter_id);
|
||||
const auto* metric_ptr = rocprofiler::common::get_val(id_map, base_metric_id);
|
||||
if(!metric_ptr) return ROCPROFILER_STATUS_ERROR_COUNTER_NOT_FOUND;
|
||||
// Don't add duplicates
|
||||
if(!already_added.emplace(metric_ptr->id()).second) continue;
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include <rocprofiler-sdk/counters.h>
|
||||
#include <rocprofiler-sdk/experimental/counters.h>
|
||||
#include <rocprofiler-sdk/fwd.h>
|
||||
#include <rocprofiler-sdk/cxx/constants.hpp>
|
||||
#include <rocprofiler-sdk/cxx/operators.hpp>
|
||||
|
||||
#include <fmt/core.h>
|
||||
@@ -86,6 +87,28 @@ get_static_ptr_array(const std::vector<Tp>& vec)
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Helper function to extract agent_id from agent-encoded counter_id
|
||||
// Returns agent_id with handle=0 if not found
|
||||
rocprofiler_agent_id_t
|
||||
get_agent_id_from_counter_id(rocprofiler_counter_id_t counter_id)
|
||||
{
|
||||
// Extract logical_node_id from counter ID encoding
|
||||
auto agent_index = get_agent_from_counter_id(counter_id) - AGENT_ENCODING_OFFSET;
|
||||
|
||||
// Find the agent with matching logical_node_id
|
||||
for(const auto* agent : rocprofiler::agent::get_agents())
|
||||
{
|
||||
if(agent && agent->logical_node_id == agent_index)
|
||||
{
|
||||
return agent->id;
|
||||
}
|
||||
}
|
||||
|
||||
// Return invalid agent_id if not found
|
||||
return sdk::null_agent_id;
|
||||
}
|
||||
|
||||
} // namespace counters
|
||||
} // namespace rocprofiler
|
||||
|
||||
@@ -113,8 +136,11 @@ rocprofiler_query_counter_info(rocprofiler_counter_id_t counter_id,
|
||||
auto metrics_map = counters::loadMetrics();
|
||||
const auto& id_map = metrics_map->id_to_metric;
|
||||
|
||||
// Extract base metric ID from counter_id (handles agent-encoded counter IDs)
|
||||
auto base_metric_id = counters::get_base_metric_from_counter_id(counter_id);
|
||||
|
||||
auto base_info = [&](auto& out_struct) {
|
||||
if(const auto* metric_ptr = common::get_val(id_map, counter_id.handle))
|
||||
if(const auto* metric_ptr = common::get_val(id_map, static_cast<uint64_t>(base_metric_id)))
|
||||
{
|
||||
out_struct.id = counter_id;
|
||||
out_struct.is_constant = (metric_ptr->constant().empty()) ? 0 : 1;
|
||||
@@ -128,10 +154,13 @@ rocprofiler_query_counter_info(rocprofiler_counter_id_t counter_id,
|
||||
return false;
|
||||
};
|
||||
|
||||
auto dim_info = [&](auto& out_struct) {
|
||||
auto dim_ptr = counters::get_dimension_cache();
|
||||
auto dim_info = [&](auto& out_struct, rocprofiler_agent_id_t agent_id) {
|
||||
auto dim_ptr = counters::get_dimension_cache(agent_id);
|
||||
if(!dim_ptr) return false;
|
||||
|
||||
const auto* dims = common::get_val(dim_ptr->id_to_dim, counter_id.handle);
|
||||
// Use base metric ID for dimension lookup
|
||||
const auto* dims =
|
||||
common::get_val(dim_ptr->id_to_dim, static_cast<uint64_t>(base_metric_id));
|
||||
if(!dims) return false;
|
||||
|
||||
auto _dim_info = std::vector<rocprofiler_counter_record_dimension_info_t>{};
|
||||
@@ -159,10 +188,17 @@ rocprofiler_query_counter_info(rocprofiler_counter_id_t counter_id,
|
||||
|
||||
// Construct all possible permutations of instance ids. This is every instance
|
||||
// that can be returned by the counter across all dimensions.
|
||||
// Note: Dimensions are agent-specific. This function uses the agent from counter ID encoding.
|
||||
auto dim_permutations = [&](auto& out_struct) {
|
||||
auto dim_ptr = counters::get_dimension_cache();
|
||||
// Get agent from counter ID encoding
|
||||
auto agent_id = counters::get_agent_id_from_counter_id(counter_id);
|
||||
if(agent_id == rocprofiler::sdk::null_agent_id) return false;
|
||||
|
||||
const auto* dims = common::get_val(dim_ptr->id_to_dim, counter_id.handle);
|
||||
auto dim_ptr = counters::get_dimension_cache(agent_id);
|
||||
if(!dim_ptr) return false;
|
||||
// Use base metric ID for dimension lookup
|
||||
const auto* dims =
|
||||
common::get_val(dim_ptr->id_to_dim, static_cast<uint64_t>(base_metric_id));
|
||||
if(!dims) return false;
|
||||
|
||||
auto instances = std::vector<rocprofiler_counter_record_dimension_instance_info_t>{};
|
||||
@@ -191,6 +227,7 @@ rocprofiler_query_counter_info(rocprofiler_counter_id_t counter_id,
|
||||
{
|
||||
auto& rec = instances.emplace_back();
|
||||
counters::set_dim_in_rec(rec.instance_id, metric_dim.type(), i);
|
||||
// Store full agent-encoded counter ID in instance record
|
||||
counters::set_counter_in_rec(rec.instance_id, counter_id);
|
||||
}
|
||||
}
|
||||
@@ -204,6 +241,7 @@ rocprofiler_query_counter_info(rocprofiler_counter_id_t counter_id,
|
||||
{
|
||||
auto& rec = tmp.emplace_back(instance);
|
||||
counters::set_dim_in_rec(rec.instance_id, metric_dim.type(), i);
|
||||
// Store full agent-encoded counter ID in instance record
|
||||
counters::set_counter_in_rec(rec.instance_id, counter_id);
|
||||
}
|
||||
}
|
||||
@@ -233,8 +271,9 @@ rocprofiler_query_counter_info(rocprofiler_counter_id_t counter_id,
|
||||
}
|
||||
instance.dimensions = counters::get_static_ptr_array(dimensions);
|
||||
instance.dimensions_count = std::size(_dim_info);
|
||||
instance.counter_id = counters::rec_to_counter_id(instance_id).handle;
|
||||
instance.size = rocprofiler_counter_record_dimension_instance_v1_info_t_rt_size;
|
||||
// Extract the counter_id from the instance_id
|
||||
instance.counter_id = counters::rec_to_counter_id(instance.instance_id).handle;
|
||||
instance.size = rocprofiler_counter_record_dimension_instance_v1_info_t_rt_size;
|
||||
}
|
||||
out_struct.dimensions_instances = counters::get_static_ptr_array(instances);
|
||||
out_struct.dimensions_instances_count = instances.size();
|
||||
@@ -257,7 +296,12 @@ rocprofiler_query_counter_info(rocprofiler_counter_id_t counter_id,
|
||||
auto& _out_struct = *static_cast<rocprofiler_counter_info_v1_t*>(info);
|
||||
|
||||
if(!base_info(_out_struct)) return ROCPROFILER_STATUS_ERROR_COUNTER_NOT_FOUND;
|
||||
if(!dim_info(_out_struct)) return ROCPROFILER_STATUS_ERROR_DIM_NOT_FOUND;
|
||||
|
||||
// Get agent from counter ID encoding
|
||||
auto agent_id = counters::get_agent_id_from_counter_id(counter_id);
|
||||
if(agent_id.handle == 0) return ROCPROFILER_STATUS_ERROR_AGENT_NOT_FOUND;
|
||||
|
||||
if(!dim_info(_out_struct, agent_id)) return ROCPROFILER_STATUS_ERROR_DIM_NOT_FOUND;
|
||||
if(!dim_permutations(_out_struct)) return ROCPROFILER_STATUS_ERROR_DIM_NOT_FOUND;
|
||||
|
||||
return ROCPROFILER_STATUS_SUCCESS;
|
||||
@@ -281,14 +325,17 @@ rocprofiler_query_counter_info(rocprofiler_counter_id_t counter_id,
|
||||
* @return rocprofiler_status_t
|
||||
*/
|
||||
rocprofiler_status_t
|
||||
rocprofiler_query_counter_instance_count(rocprofiler_agent_id_t,
|
||||
rocprofiler_query_counter_instance_count(rocprofiler_agent_id_t agent_id,
|
||||
rocprofiler_counter_id_t counter_id,
|
||||
size_t* instance_count)
|
||||
{
|
||||
*instance_count = 0;
|
||||
auto dim_ptr = counters::get_dimension_cache();
|
||||
auto dim_ptr = counters::get_dimension_cache(agent_id);
|
||||
if(!dim_ptr) return ROCPROFILER_STATUS_ERROR_AGENT_NOT_FOUND;
|
||||
|
||||
const auto* dims = common::get_val(dim_ptr->id_to_dim, counter_id.handle);
|
||||
// Extract base metric ID from counter_id (handles agent-encoded counter IDs)
|
||||
auto base_metric_id = counters::get_base_metric_from_counter_id(counter_id);
|
||||
const auto* dims = common::get_val(dim_ptr->id_to_dim, static_cast<uint64_t>(base_metric_id));
|
||||
if(!dims) return ROCPROFILER_STATUS_ERROR_COUNTER_NOT_FOUND;
|
||||
|
||||
for(const auto& metric_dim : *dims)
|
||||
@@ -317,14 +364,18 @@ rocprofiler_iterate_agent_supported_counters(rocprofiler_agent_id_t
|
||||
const auto* agent = rocprofiler::agent::get_agent(agent_id);
|
||||
if(!agent) return ROCPROFILER_STATUS_ERROR_AGENT_NOT_FOUND;
|
||||
|
||||
auto metrics = counters::getMetricsForAgent(agent->name);
|
||||
auto metrics = counters::getMetricsForAgent(agent);
|
||||
if(metrics.empty()) return ROCPROFILER_STATUS_ERROR_AGENT_ARCH_NOT_SUPPORTED;
|
||||
|
||||
std::vector<rocprofiler_counter_id_t> ids;
|
||||
ids.reserve(metrics.size());
|
||||
for(const auto& metric : metrics)
|
||||
{
|
||||
ids.push_back({.handle = metric.id()});
|
||||
// Create agent-encoded counter ID using the agent's logical_node_id
|
||||
rocprofiler_counter_id_t counter_id{.handle = 0};
|
||||
counters::set_base_metric_in_counter_id(counter_id, metric.id());
|
||||
counters::set_agent_in_counter_id(counter_id, agent->logical_node_id);
|
||||
ids.push_back(counter_id);
|
||||
}
|
||||
|
||||
return cb(agent_id, ids.data(), ids.size(), user_data);
|
||||
@@ -341,8 +392,21 @@ rocprofiler_status_t
|
||||
rocprofiler_query_record_counter_id(rocprofiler_counter_instance_id_t id,
|
||||
rocprofiler_counter_id_t* counter_id)
|
||||
{
|
||||
// Get counter id from record
|
||||
*counter_id = counters::rec_to_counter_id(id);
|
||||
// Get base metric ID from instance record (bits 63-48)
|
||||
uint16_t base_metric = static_cast<uint16_t>(id >> counters::DIM_BIT_LENGTH);
|
||||
|
||||
// Try to get agent encoding from ROCPROFILER_DIMENSION_AGENT dimension field
|
||||
uint8_t agent_encoded =
|
||||
static_cast<uint8_t>(counters::rec_to_dim_pos(id, counters::ROCPROFILER_DIMENSION_AGENT));
|
||||
|
||||
// Reconstruct full agent-encoded counter ID
|
||||
// Note: agent_encoded includes the offset, but set_agent_in_counter_id() adds the offset,
|
||||
// so we need to subtract it first to get the raw logical_node_id
|
||||
counter_id->handle = 0;
|
||||
counters::set_base_metric_in_counter_id(*counter_id, base_metric);
|
||||
counters::set_agent_in_counter_id(
|
||||
*counter_id, agent_encoded > 0 ? agent_encoded - counters::AGENT_ENCODING_OFFSET : 0);
|
||||
|
||||
return ROCPROFILER_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -361,9 +425,17 @@ rocprofiler_iterate_counter_dimensions(rocprofiler_counter_id_t id,
|
||||
rocprofiler_available_dimensions_cb_t info_cb,
|
||||
void* user_data)
|
||||
{
|
||||
auto dim_ptr = counters::get_dimension_cache();
|
||||
// Extract base metric ID from counter_id (handles agent-encoded counter IDs)
|
||||
auto base_metric_id = counters::get_base_metric_from_counter_id(id);
|
||||
|
||||
const auto* dims = common::get_val(dim_ptr->id_to_dim, id.handle);
|
||||
// Get agent from counter ID encoding
|
||||
auto agent_id = counters::get_agent_id_from_counter_id(id);
|
||||
if(agent_id.handle == 0) return ROCPROFILER_STATUS_ERROR_AGENT_NOT_FOUND;
|
||||
|
||||
auto dim_ptr = counters::get_dimension_cache(agent_id);
|
||||
if(!dim_ptr) return ROCPROFILER_STATUS_ERROR_AGENT_NOT_FOUND;
|
||||
// Use base metric ID for dimension lookup
|
||||
const auto* dims = common::get_val(dim_ptr->id_to_dim, static_cast<uint64_t>(base_metric_id));
|
||||
if(!dims) return ROCPROFILER_STATUS_ERROR_COUNTER_NOT_FOUND;
|
||||
|
||||
// This is likely faster than a map lookup given the limited number of dims.
|
||||
@@ -436,11 +508,11 @@ rocprofiler_create_counter(const char* name,
|
||||
}
|
||||
|
||||
counter_id->handle = add_metric->arch_to_metric.at(agent_ptr->name).back().id();
|
||||
// Regenerate ASTs and Dimension Cache
|
||||
// Regenerate ASTs and Dimension Cache for this agent
|
||||
try
|
||||
{
|
||||
counters::get_ast_map(true);
|
||||
counters::get_dimension_cache(true);
|
||||
counters::get_dimension_cache(agent, true);
|
||||
} catch(std::exception& e)
|
||||
{
|
||||
ROCP_FATAL << "Could not regenerate ASTs and Dimension Cache " << e.what();
|
||||
|
||||
@@ -96,7 +96,7 @@ counter_callback_info::setup_counter_config(std::shared_ptr<counter_config>& pro
|
||||
|
||||
try
|
||||
{
|
||||
config.asts.back().set_dimensions();
|
||||
config.asts.back().set_dimensions(config.agent->id);
|
||||
} catch(std::runtime_error& e)
|
||||
{
|
||||
ROCP_ERROR << metric.name() << " has improper dimensions"
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
|
||||
#include <rocprofiler-sdk/fwd.h>
|
||||
#include <rocprofiler-sdk/rocprofiler.h>
|
||||
#include <rocprofiler-sdk/cxx/hash.hpp>
|
||||
#include <rocprofiler-sdk/cxx/operators.hpp>
|
||||
|
||||
#include <fmt/core.h>
|
||||
|
||||
@@ -42,7 +44,7 @@ namespace rocprofiler
|
||||
namespace counters
|
||||
{
|
||||
std::vector<MetricDimension>
|
||||
getBlockDimensions(std::string_view agent, const Metric& metric)
|
||||
getBlockDimensions(rocprofiler_agent_id_t agent_id, const Metric& metric)
|
||||
{
|
||||
if(!metric.constant().empty())
|
||||
{
|
||||
@@ -56,32 +58,25 @@ getBlockDimensions(std::string_view agent, const Metric& metric)
|
||||
|
||||
std::vector<MetricDimension> ret;
|
||||
|
||||
for(const auto* maybe_agent : rocprofiler::agent::get_agents())
|
||||
aql::CounterPacketConstruct pkt_gen(agent_id, {metric});
|
||||
const auto& events = pkt_gen.get_counter_events(metric);
|
||||
|
||||
for(const auto& event : events)
|
||||
{
|
||||
if(std::string(maybe_agent->name) == agent)
|
||||
auto dims = std::map<int, uint64_t>{};
|
||||
auto status = aql::get_dim_info(agent_id, event, 0, dims);
|
||||
CHECK_EQ(status, ROCPROFILER_STATUS_SUCCESS) << rocprofiler_get_status_string(status);
|
||||
|
||||
for(const auto& [id, extent] : dims)
|
||||
{
|
||||
aql::CounterPacketConstruct pkt_gen(maybe_agent->id, {metric});
|
||||
const auto& events = pkt_gen.get_counter_events(metric);
|
||||
|
||||
for(const auto& event : events)
|
||||
if(const auto* inst_type =
|
||||
rocprofiler::common::get_val(aqlprofile_id_to_rocprof_instance(), id))
|
||||
{
|
||||
std::map<int, uint64_t> dims;
|
||||
auto status = aql::get_dim_info(maybe_agent->id, event, 0, dims);
|
||||
CHECK_EQ(status, ROCPROFILER_STATUS_SUCCESS)
|
||||
<< rocprofiler_get_status_string(status);
|
||||
|
||||
for(const auto& [id, extent] : dims)
|
||||
{
|
||||
if(const auto* inst_type =
|
||||
rocprofiler::common::get_val(aqlprofile_id_to_rocprof_instance(), id))
|
||||
{
|
||||
count.emplace(*inst_type, 0).first->second = extent;
|
||||
}
|
||||
else
|
||||
{
|
||||
ROCP_WARNING << "Unknown AQL Profiler Dimension " << id << " " << extent;
|
||||
}
|
||||
}
|
||||
count.emplace(*inst_type, 0).first->second = extent;
|
||||
}
|
||||
else
|
||||
{
|
||||
ROCP_WARNING << "Unknown AQL Profiler Dimension " << id << " " << extent;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -98,24 +93,30 @@ getBlockDimensions(std::string_view agent, const Metric& metric)
|
||||
namespace
|
||||
{
|
||||
metric_dims
|
||||
generate_dimensions()
|
||||
generate_dimensions(rocprofiler_agent_id_t agent_id)
|
||||
{
|
||||
std::unordered_map<uint64_t, std::vector<MetricDimension>> dims;
|
||||
|
||||
const auto asts = counters::get_ast_map();
|
||||
for(const auto& [gfx, metrics] : asts->arch_to_counter_asts)
|
||||
// Get the agent to determine which architecture's metrics to load
|
||||
const auto* agent = rocprofiler::agent::get_agent(agent_id);
|
||||
if(!agent) return {.id_to_dim = dims};
|
||||
|
||||
const auto asts = counters::get_ast_map();
|
||||
const auto* arch_asts =
|
||||
rocprofiler::common::get_val(asts->arch_to_counter_asts, std::string(agent->name));
|
||||
if(!arch_asts) return {.id_to_dim = dims};
|
||||
|
||||
for(const auto& [metric, ast] : *arch_asts)
|
||||
{
|
||||
for(const auto& [metric, ast] : metrics)
|
||||
auto ast_copy = ast;
|
||||
try
|
||||
{
|
||||
auto ast_copy = ast;
|
||||
try
|
||||
{
|
||||
dims.emplace(ast.out_id().handle, ast_copy.set_dimensions());
|
||||
} catch(std::runtime_error& e)
|
||||
{
|
||||
ROCP_FATAL << metric << " has improper dimensions"
|
||||
<< " " << e.what();
|
||||
}
|
||||
// Generate dimensions for this specific agent
|
||||
dims.emplace(ast.out_id().handle, ast_copy.set_dimensions(agent_id));
|
||||
} catch(std::runtime_error& e)
|
||||
{
|
||||
ROCP_FATAL << metric << " has improper dimensions"
|
||||
<< " " << e.what();
|
||||
}
|
||||
}
|
||||
return {.id_to_dim = dims};
|
||||
@@ -123,26 +124,34 @@ generate_dimensions()
|
||||
} // namespace
|
||||
|
||||
std::shared_ptr<const metric_dims>
|
||||
get_dimension_cache(bool reload)
|
||||
get_dimension_cache(rocprofiler_agent_id_t agent_id, bool reload)
|
||||
{
|
||||
using DimSync = common::Synchronized<std::shared_ptr<const metric_dims>>;
|
||||
static DimSync*& dim_data = common::static_object<DimSync>::construct(
|
||||
[&]() { return std::make_shared<const metric_dims>(generate_dimensions()); }());
|
||||
using DimSync = common::Synchronized<
|
||||
std::unordered_map<rocprofiler_agent_id_t, std::shared_ptr<const metric_dims>>>;
|
||||
static DimSync*& dim_data = common::static_object<DimSync>::construct();
|
||||
|
||||
if(!dim_data) return nullptr;
|
||||
|
||||
if(!reload)
|
||||
// Check if we need to generate (first time or reload)
|
||||
auto needs_generation = dim_data->rlock([agent_id, reload](const auto& data) {
|
||||
return reload || !rocprofiler::common::get_val(data, agent_id);
|
||||
});
|
||||
|
||||
if(needs_generation)
|
||||
{
|
||||
return dim_data->rlock([](const auto& data) {
|
||||
CHECK(data);
|
||||
return data;
|
||||
return dim_data->wlock([agent_id](auto& data) -> std::shared_ptr<const metric_dims> {
|
||||
auto new_dims = std::make_shared<const metric_dims>(generate_dimensions(agent_id));
|
||||
data[agent_id] = new_dims;
|
||||
return new_dims;
|
||||
});
|
||||
}
|
||||
|
||||
return dim_data->wlock([&](auto& data) {
|
||||
data = std::make_shared<const metric_dims>(generate_dimensions());
|
||||
CHECK(data);
|
||||
return data;
|
||||
return dim_data->rlock([agent_id](const auto& data) -> std::shared_ptr<const metric_dims> {
|
||||
if(const auto* ptr = rocprofiler::common::get_val(data, agent_id))
|
||||
{
|
||||
return *ptr;
|
||||
}
|
||||
return nullptr;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -65,10 +65,10 @@ struct metric_dims
|
||||
|
||||
// get all dimensions for an agent, block_name
|
||||
std::vector<MetricDimension>
|
||||
getBlockDimensions(std::string_view agent, const counters::Metric&);
|
||||
getBlockDimensions(rocprofiler_agent_id_t agent_id, const counters::Metric&);
|
||||
|
||||
std::shared_ptr<const metric_dims>
|
||||
get_dimension_cache(bool reload = false);
|
||||
get_dimension_cache(rocprofiler_agent_id_t agent_id, bool reload = false);
|
||||
} // namespace counters
|
||||
} // namespace rocprofiler
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "lib/common/static_object.hpp"
|
||||
#include "lib/common/synchronized.hpp"
|
||||
#include "lib/common/utility.hpp"
|
||||
#include "lib/rocprofiler-sdk/agent.hpp"
|
||||
#include "lib/rocprofiler-sdk/counters/dimensions.hpp"
|
||||
#include "lib/rocprofiler-sdk/counters/id_decode.hpp"
|
||||
#include "lib/rocprofiler-sdk/counters/parser/raw_ast.hpp"
|
||||
@@ -134,7 +135,10 @@ perform_reduction(
|
||||
perform_reduction_to_single_instance(reduce_op, input_array, &result);
|
||||
input_array->clear();
|
||||
input_array->push_back(result);
|
||||
// Preserve DIMENSION_AGENT when reducing to single instance
|
||||
auto agent_dim = rec_to_dim_pos(result.id, ROCPROFILER_DIMENSION_AGENT);
|
||||
set_dim_in_rec(input_array->begin()->id, ROCPROFILER_DIMENSION_NONE, 0);
|
||||
set_dim_in_rec(input_array->begin()->id, ROCPROFILER_DIMENSION_AGENT, agent_dim);
|
||||
return input_array;
|
||||
}
|
||||
|
||||
@@ -167,7 +171,10 @@ perform_reduction(
|
||||
}
|
||||
if(input_array->size() == 1)
|
||||
{
|
||||
// Preserve DIMENSION_AGENT when reducing to single instance
|
||||
auto agent_dim = rec_to_dim_pos(input_array->begin()->id, ROCPROFILER_DIMENSION_AGENT);
|
||||
set_dim_in_rec(input_array->begin()->id, ROCPROFILER_DIMENSION_NONE, 0);
|
||||
set_dim_in_rec(input_array->begin()->id, ROCPROFILER_DIMENSION_AGENT, agent_dim);
|
||||
}
|
||||
return input_array;
|
||||
}
|
||||
@@ -441,14 +448,36 @@ EvaluateAST::EvaluateAST(rocprofiler_counter_id_t out_id,
|
||||
}
|
||||
|
||||
std::vector<MetricDimension>
|
||||
EvaluateAST::set_dimensions()
|
||||
EvaluateAST::set_dimensions(rocprofiler_agent_id_t agent_id)
|
||||
{
|
||||
if(!_dimension_types.empty())
|
||||
{
|
||||
return _dimension_types;
|
||||
}
|
||||
|
||||
auto get_dim_types = [&](auto& metric) { return getBlockDimensions(_agent, metric); };
|
||||
auto get_dim_types = [&](auto& metric) {
|
||||
// If agent_id is provided, use it directly
|
||||
if(agent_id.handle != 0)
|
||||
{
|
||||
return getBlockDimensions(agent_id, metric);
|
||||
}
|
||||
|
||||
// Otherwise, find an agent with matching architecture name
|
||||
// NOTE: In multi-GPU scenarios, architecture name alone is unreliable when
|
||||
// GPUs share the same architecture but have different configurations.
|
||||
ROCP_WARNING << "set_dimensions: Using architecture name fallback. In multi-GPU "
|
||||
<< "scenarios with identical architectures, this may be unreliable. "
|
||||
<< "Consider providing agent_id explicitly.";
|
||||
for(const auto* agent : rocprofiler::agent::get_agents())
|
||||
{
|
||||
if(agent && std::string(agent->name) == _agent)
|
||||
{
|
||||
return getBlockDimensions(agent->id, metric);
|
||||
}
|
||||
}
|
||||
// If no agent found, return empty dimensions
|
||||
return std::vector<MetricDimension>{};
|
||||
};
|
||||
|
||||
switch(_type)
|
||||
{
|
||||
@@ -468,8 +497,8 @@ EvaluateAST::set_dimensions()
|
||||
case MULTIPLY_NODE:
|
||||
case DIVIDE_NODE:
|
||||
{
|
||||
auto first = _children[0].set_dimensions();
|
||||
auto second = _children[1].set_dimensions();
|
||||
auto first = _children.at(0).set_dimensions(agent_id);
|
||||
auto second = _children.at(1).set_dimensions(agent_id);
|
||||
// - first.size() > 1 && second.size() > 1
|
||||
// This is an explicit compatibility change to allow existing integer * COUNTER
|
||||
// derived counters to function
|
||||
@@ -477,9 +506,9 @@ EvaluateAST::set_dimensions()
|
||||
throw std::runtime_error(
|
||||
fmt::format("Dimension mis-mismatch: {} (dims: {}) and {} (dims: {})",
|
||||
_children[0].metric(),
|
||||
fmt::join(_children[0].set_dimensions(), ","),
|
||||
fmt::join(_children[0].set_dimensions(agent_id), ","),
|
||||
_children[1].metric(),
|
||||
fmt::join(_children[1].set_dimensions(), ",")));
|
||||
fmt::join(_children[1].set_dimensions(agent_id), ",")));
|
||||
_dimension_types = first.size() > second.size() ? first : second;
|
||||
}
|
||||
break;
|
||||
@@ -505,7 +534,7 @@ EvaluateAST::set_dimensions()
|
||||
{dimension_map().at(ROCPROFILER_DIMENSION_INSTANCE),
|
||||
1,
|
||||
ROCPROFILER_DIMENSION_INSTANCE}};
|
||||
auto first = _children[0].set_dimensions();
|
||||
auto first = _children[0].set_dimensions(agent_id);
|
||||
first.erase(std::remove_if(first.begin(),
|
||||
first.end(),
|
||||
[&](const MetricDimension& dim) {
|
||||
@@ -519,7 +548,7 @@ EvaluateAST::set_dimensions()
|
||||
break;
|
||||
case SELECT_NODE:
|
||||
{
|
||||
auto first = _children[0].set_dimensions();
|
||||
auto first = _children[0].set_dimensions(agent_id);
|
||||
first.erase(std::remove_if(first.begin(),
|
||||
first.end(),
|
||||
[&](const MetricDimension& dim) {
|
||||
@@ -706,7 +735,10 @@ EvaluateAST::read_special_counters(
|
||||
if(!out_map[metric.id()].empty()) out_map[metric.id()].clear();
|
||||
auto& record = out_map[metric.id()].emplace_back();
|
||||
set_counter_in_rec(record.id, {.handle = metric.id()});
|
||||
set_dim_in_rec(record.id, ROCPROFILER_DIMENSION_NONE, 0);
|
||||
// Don't use DIMENSION_NONE as it overwrites the DIMENSION_AGENT field
|
||||
// Instead, explicitly set DIMENSION_AGENT with the agent's logical_node_id
|
||||
set_dim_in_rec(
|
||||
record.id, ROCPROFILER_DIMENSION_AGENT, agent.logical_node_id + AGENT_ENCODING_OFFSET);
|
||||
|
||||
record.counter_value = get_agent_property(metric.name(), agent);
|
||||
}
|
||||
@@ -746,6 +778,13 @@ EvaluateAST::read_pkt(const aql::CounterPacketConstruct* pkt_gen, hsa::AQLPacket
|
||||
CHECK_EQ(aql_status, ROCPROFILER_STATUS_SUCCESS)
|
||||
<< rocprofiler_get_status_string(aql_status);
|
||||
|
||||
// Set DIMENSION_AGENT with the agent's logical_node_id
|
||||
auto agent_id = it.pkt_gen->agent();
|
||||
const auto* agent = CHECK_NOTNULL(rocprofiler::agent::get_agent(agent_id));
|
||||
set_dim_in_rec(next_rec.id,
|
||||
ROCPROFILER_DIMENSION_AGENT,
|
||||
agent->logical_node_id + AGENT_ENCODING_OFFSET);
|
||||
|
||||
// set_dim_in_rec(next_rec.id, ROCPROFILER_DIMENSION_NONE, vec.size() - 1);
|
||||
// Note: in the near future we need to use hw_counter here instead
|
||||
next_rec.counter_value = counter_value;
|
||||
@@ -765,7 +804,14 @@ EvaluateAST::set_out_id(std::vector<rocprofiler_counter_record_t>& results) cons
|
||||
{
|
||||
for(auto& record : results)
|
||||
{
|
||||
// Preserve the agent encoding from the instance record
|
||||
auto agent_encoded = rec_to_dim_pos(record.id, ROCPROFILER_DIMENSION_AGENT);
|
||||
|
||||
// Update the counter ID (this will overwrite DIMENSION_AGENT)
|
||||
set_counter_in_rec(record.id, _out_id);
|
||||
|
||||
// Restore the agent encoding that was in the original record
|
||||
set_dim_in_rec(record.id, ROCPROFILER_DIMENSION_AGENT, agent_encoded);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -102,9 +102,10 @@ public:
|
||||
* of this AST. Can throw if the AST is invalid (i.e. dimension mismatch in
|
||||
* child nodes of this AST). This is done in a recursive fashion.
|
||||
*
|
||||
* @param agent_id Agent ID to use for dimension lookup.
|
||||
* @return std::vector<MetricDimension> dimension of the output of this AST.
|
||||
*/
|
||||
std::vector<MetricDimension> set_dimensions();
|
||||
std::vector<MetricDimension> set_dimensions(rocprofiler_agent_id_t agent_id);
|
||||
|
||||
bool validate_raw_ast(const std::unordered_map<std::string, Metric>& metrics);
|
||||
|
||||
|
||||
@@ -89,5 +89,51 @@ aqlprofile_id_to_rocprof_instance()
|
||||
return *aql_to_rocprof_dims;
|
||||
}
|
||||
|
||||
// Counter ID encoding/decoding implementations
|
||||
void
|
||||
set_agent_in_counter_id(rocprofiler_counter_id_t& id, uint8_t agent_logical_node_id)
|
||||
{
|
||||
// Check that logical_node_id + offset fits in 6 bits
|
||||
// With AGENT_ENCODING_OFFSET=1, this allows logical_node_id 0-62 (63 agents)
|
||||
CHECK(agent_logical_node_id < ((1 << AGENT_BIT_LENGTH) - AGENT_ENCODING_OFFSET))
|
||||
<< "Agent logical_node_id " << static_cast<int>(agent_logical_node_id)
|
||||
<< " exceeds limit (max " << ((1 << AGENT_BIT_LENGTH) - AGENT_ENCODING_OFFSET - 1)
|
||||
<< " to allow for encoding offset)";
|
||||
|
||||
// Add encoding offset to ensure agent 0 is detectable (non-zero)
|
||||
uint8_t agent_encoded = agent_logical_node_id + AGENT_ENCODING_OFFSET;
|
||||
|
||||
// Clear agent bits and set new value
|
||||
id.handle = (id.handle & ~(AGENT_MASK << AGENT_BIT_OFFSET)) |
|
||||
(static_cast<uint64_t>(agent_encoded) << AGENT_BIT_OFFSET);
|
||||
}
|
||||
|
||||
uint8_t
|
||||
get_agent_from_counter_id(rocprofiler_counter_id_t id)
|
||||
{
|
||||
return static_cast<uint8_t>((id.handle >> AGENT_BIT_OFFSET) & AGENT_MASK);
|
||||
}
|
||||
|
||||
void
|
||||
set_base_metric_in_counter_id(rocprofiler_counter_id_t& id, uint16_t metric_id)
|
||||
{
|
||||
CHECK(metric_id <= BASE_METRIC_MASK) << "Base metric ID exceeds 16-bit limit";
|
||||
// Clear base metric bits and set new value
|
||||
id.handle = (id.handle & ~BASE_METRIC_MASK) | metric_id;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
get_base_metric_from_counter_id(rocprofiler_counter_id_t id)
|
||||
{
|
||||
return static_cast<uint16_t>(id.handle & BASE_METRIC_MASK);
|
||||
}
|
||||
|
||||
bool
|
||||
is_agent_encoded_counter_id(rocprofiler_counter_id_t id)
|
||||
{
|
||||
// Check if agent bits are non-zero
|
||||
return ((id.handle >> AGENT_BIT_OFFSET) & AGENT_MASK) != 0;
|
||||
}
|
||||
|
||||
} // namespace counters
|
||||
} // namespace rocprofiler
|
||||
|
||||
@@ -44,10 +44,10 @@ enum rocprofiler_profile_counter_instance_types
|
||||
ROCPROFILER_DIMENSION_XCC, ///< XCC dimension of result
|
||||
ROCPROFILER_DIMENSION_AID, ///< AID dimension of result
|
||||
ROCPROFILER_DIMENSION_SHADER_ENGINE, ///< SE dimension of result
|
||||
ROCPROFILER_DIMENSION_AGENT, ///< Agent dimension
|
||||
ROCPROFILER_DIMENSION_SHADER_ARRAY, ///< Number of shader arrays
|
||||
ROCPROFILER_DIMENSION_WGP, ///< Number of workgroup processors
|
||||
ROCPROFILER_DIMENSION_INSTANCE, ///< Number of instances
|
||||
ROCPROFILER_DIMENSION_AGENT, ///< Agent dimension (internal use only - do not set externally)
|
||||
ROCPROFILER_DIMENSION_SHADER_ARRAY, ///< Number of shader arrays
|
||||
ROCPROFILER_DIMENSION_WGP, ///< Number of workgroup processors
|
||||
ROCPROFILER_DIMENSION_INSTANCE, ///< Number of instances
|
||||
ROCPROFILER_DIMENSION_LAST
|
||||
};
|
||||
|
||||
@@ -70,19 +70,53 @@ inline size_t
|
||||
rec_to_dim_pos(rocprofiler_counter_instance_id_t id,
|
||||
rocprofiler_profile_counter_instance_types dim);
|
||||
|
||||
// Counter ID encoding/decoding functions for agent-specific counter IDs
|
||||
void
|
||||
set_agent_in_counter_id(rocprofiler_counter_id_t& id, uint8_t agent_logical_node_id);
|
||||
uint8_t
|
||||
get_agent_from_counter_id(rocprofiler_counter_id_t id);
|
||||
void
|
||||
set_base_metric_in_counter_id(rocprofiler_counter_id_t& id, uint16_t metric_id);
|
||||
uint16_t
|
||||
get_base_metric_from_counter_id(rocprofiler_counter_id_t id);
|
||||
bool
|
||||
is_agent_encoded_counter_id(rocprofiler_counter_id_t id);
|
||||
|
||||
// Counter ID encoding constants
|
||||
constexpr uint64_t AGENT_BIT_OFFSET = 32;
|
||||
constexpr uint64_t AGENT_BIT_LENGTH = 6;
|
||||
constexpr uint64_t BASE_METRIC_BIT_LENGTH = 16;
|
||||
constexpr uint64_t AGENT_MASK = ((1ULL << AGENT_BIT_LENGTH) - 1);
|
||||
constexpr uint64_t BASE_METRIC_MASK = ((1ULL << BASE_METRIC_BIT_LENGTH) - 1);
|
||||
constexpr uint8_t AGENT_ENCODING_OFFSET = 1; // Offset to reserve 0 for detection
|
||||
|
||||
const std::unordered_map<int, rocprofiler_profile_counter_instance_types>&
|
||||
aqlprofile_id_to_rocprof_instance();
|
||||
|
||||
} // namespace counters
|
||||
} // namespace rocprofiler
|
||||
|
||||
inline rocprofiler_counter_id_t
|
||||
rocprofiler_counter_id_t
|
||||
rocprofiler::counters::rec_to_counter_id(rocprofiler_counter_instance_id_t id)
|
||||
{
|
||||
return {.handle = id >> DIM_BIT_LENGTH};
|
||||
// Extract base metric ID from instance record (bits 63-48)
|
||||
uint16_t base_metric = static_cast<uint16_t>(id >> DIM_BIT_LENGTH);
|
||||
|
||||
// Extract agent encoding from ROCPROFILER_DIMENSION_AGENT dimension field
|
||||
uint8_t agent_encoded = static_cast<uint8_t>(rec_to_dim_pos(id, ROCPROFILER_DIMENSION_AGENT));
|
||||
|
||||
// Reconstruct full agent-encoded counter ID
|
||||
// Note: agent_encoded includes the offset, but set_agent_in_counter_id() adds the offset,
|
||||
// so we need to subtract it first to get the raw logical_node_id
|
||||
rocprofiler_counter_id_t counter_id{.handle = 0};
|
||||
set_base_metric_in_counter_id(counter_id, base_metric);
|
||||
set_agent_in_counter_id(counter_id,
|
||||
agent_encoded > 0 ? agent_encoded - AGENT_ENCODING_OFFSET : 0);
|
||||
|
||||
return counter_id;
|
||||
}
|
||||
|
||||
inline void
|
||||
void
|
||||
rocprofiler::counters::set_dim_in_rec(rocprofiler_counter_instance_id_t& id,
|
||||
rocprofiler_profile_counter_instance_types dim,
|
||||
size_t value)
|
||||
@@ -110,19 +144,32 @@ rocprofiler::counters::set_dim_in_rec(rocprofiler_counter_instance_id_t&
|
||||
<< "Dimension value exceeds max allowed";
|
||||
}
|
||||
|
||||
inline void
|
||||
void
|
||||
rocprofiler::counters::set_counter_in_rec(rocprofiler_counter_instance_id_t& id,
|
||||
rocprofiler_counter_id_t value)
|
||||
{
|
||||
// Maximum counter value given the current setup.
|
||||
CHECK(value.handle <= 0xffff) << "Counter id exceeds max allowed";
|
||||
// Reset bits to 0 for counter id
|
||||
// Extract base metric from agent-encoded counter ID
|
||||
uint16_t base_metric = get_base_metric_from_counter_id(value);
|
||||
|
||||
// Maximum counter value given the current setup (16-bit field)
|
||||
CHECK(base_metric <= 0xffff) << "Base metric ID exceeds max allowed";
|
||||
|
||||
// Reset bits to 0 for counter id (bits 63-48)
|
||||
id = id & ~((MAX_64 >> (BITS_IN_UINT64 - DIM_BIT_LENGTH)) << (DIM_BIT_LENGTH));
|
||||
// Set the value for the dimenstion
|
||||
id = id | (value.handle << (DIM_BIT_LENGTH));
|
||||
// Set the base metric ID in bits 63-48
|
||||
id = id | (static_cast<uint64_t>(base_metric) << DIM_BIT_LENGTH);
|
||||
|
||||
// Store agent encoding in ROCPROFILER_DIMENSION_AGENT dimension field
|
||||
// NOTE: ROCPROFILER_DIMENSION_AGENT is a special dimension used to store agent information
|
||||
// This field is for internal use only and should not be set by external code
|
||||
uint8_t agent_encoded = get_agent_from_counter_id(value);
|
||||
|
||||
// Unconditionally set DIMENSION_AGENT, even if agent_encoded is 0
|
||||
// (This preserves the agent encoding for all counter IDs)
|
||||
set_dim_in_rec(id, ROCPROFILER_DIMENSION_AGENT, agent_encoded);
|
||||
}
|
||||
|
||||
inline size_t
|
||||
size_t
|
||||
rocprofiler::counters::rec_to_dim_pos(rocprofiler_counter_instance_id_t id,
|
||||
rocprofiler_profile_counter_instance_types dim)
|
||||
{
|
||||
@@ -136,3 +183,27 @@ rocprofiler::counters::rec_to_dim_pos(rocprofiler_counter_instance_id_t
|
||||
id = id & ((MAX_64 >> (BITS_IN_UINT64 - bit_length)) << ((dim - 1) * bit_length));
|
||||
return id >> ((dim - 1) * bit_length);
|
||||
}
|
||||
|
||||
// Counter ID encoding/decoding implementations
|
||||
//
|
||||
// NEW COUNTER ID REPRESENTATION (Agent-Specific Counter IDs):
|
||||
// ============================================================
|
||||
// Counter IDs (rocprofiler_counter_id_t::handle, 64-bit) are now agent-specific.
|
||||
// The counter ID encodes both the base metric ID and the agent's logical_node_id.
|
||||
//
|
||||
// Bit Layout:
|
||||
// Bits 63-38: Reserved/unused (26 bits)
|
||||
// Bits 37-32: Agent logical_node_id (6 bits) - supports up to 64 agents
|
||||
// Bits 31-16: Reserved/unused (16 bits)
|
||||
// Bits 15-0: Base metric ID (16 bits) - architecture-based metric identifier
|
||||
//
|
||||
// Rationale:
|
||||
// - Allows unique counter IDs for agents with same architecture but different configurations
|
||||
// (e.g., same gfx90a but different CU counts: 110 vs 104)
|
||||
// - Maintains consistency: counter IDs are now agent-specific, matching agent-specific dimensions
|
||||
// - Agent encoding is mandatory: All counter IDs must have agent encoding (agent bits != 0)
|
||||
//
|
||||
// Usage:
|
||||
// - use set_agent_in_counter_id() / set_base_metric_in_counter_id() to encode
|
||||
// - use get_agent_from_counter_id() / get_base_metric_from_counter_id() to decode
|
||||
// - use is_agent_encoded_counter_id() to check if counter ID has agent encoding
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
// THE SOFTWARE.
|
||||
|
||||
#include "metrics.hpp"
|
||||
#include "id_decode.hpp"
|
||||
|
||||
#include "lib/common/filesystem.hpp"
|
||||
#include "lib/common/logging.hpp"
|
||||
@@ -343,12 +344,34 @@ getPerfCountersIdMap()
|
||||
}
|
||||
|
||||
std::vector<Metric>
|
||||
getMetricsForAgent(const std::string& agent)
|
||||
getMetricsForAgent(const rocprofiler_agent_t* agent)
|
||||
{
|
||||
auto mets = loadMetrics();
|
||||
if(const auto* metric_ptr = rocprofiler::common::get_val(mets->arch_to_metric, agent))
|
||||
if(const auto* metric_ptr =
|
||||
rocprofiler::common::get_val(mets->arch_to_metric, std::string(agent->name)))
|
||||
{
|
||||
return *metric_ptr;
|
||||
// Clone metrics and encode agent-specific counter IDs
|
||||
std::vector<Metric> agent_specific_metrics;
|
||||
agent_specific_metrics.reserve(metric_ptr->size());
|
||||
|
||||
for(const auto& base_metric : *metric_ptr)
|
||||
{
|
||||
Metric agent_metric = base_metric;
|
||||
|
||||
// Encode agent into counter ID using agent's logical_node_id + AGENT_ENCODING_OFFSET.
|
||||
// We add offset so that agent 0 has non-zero encoding and is detectable as
|
||||
// agent-encoded. Only logical_node_id values 0-62 (i.e., 63 agents) are supported,
|
||||
// since adding AGENT_ENCODING_OFFSET (1) results in encoded values 1-63, which fit in a
|
||||
// 6-bit field.
|
||||
rocprofiler_counter_id_t new_id{.handle = 0};
|
||||
set_base_metric_in_counter_id(new_id, base_metric.id());
|
||||
set_agent_in_counter_id(new_id, static_cast<uint8_t>(agent->logical_node_id));
|
||||
|
||||
agent_metric.set_id(new_id.handle);
|
||||
agent_specific_metrics.push_back(agent_metric);
|
||||
}
|
||||
|
||||
return agent_specific_metrics;
|
||||
}
|
||||
|
||||
return std::vector<Metric>{};
|
||||
@@ -359,7 +382,14 @@ checkValidMetric(const std::string& agent, const Metric& metric)
|
||||
{
|
||||
auto metrics = loadMetrics();
|
||||
const auto* agent_map = common::get_val(metrics->arch_to_id, agent);
|
||||
return agent_map != nullptr && agent_map->count(metric.id()) > 0;
|
||||
|
||||
// Extract base metric ID if counter ID is agent-encoded
|
||||
rocprofiler_counter_id_t counter_id{.handle = metric.id()};
|
||||
uint64_t base_metric_id = is_agent_encoded_counter_id(counter_id)
|
||||
? get_base_metric_from_counter_id(counter_id)
|
||||
: metric.id();
|
||||
|
||||
return agent_map != nullptr && agent_map->count(base_metric_id) > 0;
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <rocprofiler-sdk/agent.h>
|
||||
#include <rocprofiler-sdk/fwd.h>
|
||||
|
||||
#include <fmt/core.h>
|
||||
@@ -64,6 +65,7 @@ public:
|
||||
bool empty() const { return empty_; }
|
||||
|
||||
void setflags(uint32_t flags) { this->flags_ = flags; }
|
||||
void set_id(uint64_t id) { this->id_ = id; }
|
||||
|
||||
friend bool operator<(Metric const& lhs, Metric const& rhs);
|
||||
friend bool operator==(Metric const& lhs, Metric const& rhs);
|
||||
@@ -103,11 +105,12 @@ std::shared_ptr<const counter_metrics_t>
|
||||
loadMetrics(bool reload = false, std::optional<ArchMetric> add_metric = std::nullopt);
|
||||
|
||||
/**
|
||||
* Get the metrics that apply to a specific agent. Supplied parameter
|
||||
* is the GFXIP of the agent.
|
||||
* Get the metrics that apply to a specific agent.
|
||||
* The returned metrics will have counter IDs that are unique per agent
|
||||
* (encoding both base metric ID and agent's logical_node_id).
|
||||
*/
|
||||
std::vector<Metric>
|
||||
getMetricsForAgent(const std::string&);
|
||||
getMetricsForAgent(const rocprofiler_agent_t* agent);
|
||||
|
||||
/**
|
||||
* Get the metric event ids for perfcounters options in thread trace
|
||||
|
||||
@@ -96,6 +96,15 @@ proccess_completed_cb(completed_cb_params_t&& params)
|
||||
CHECK(ret);
|
||||
ast.set_out_id(*ret);
|
||||
|
||||
// Ensure all output records have proper agent encoding in DIMENSION_AGENT
|
||||
for(auto& val : *ret)
|
||||
{
|
||||
counters::set_dim_in_rec(
|
||||
val.id,
|
||||
counters::ROCPROFILER_DIMENSION_AGENT,
|
||||
prof_config->agent->logical_node_id + counters::AGENT_ENCODING_OFFSET);
|
||||
}
|
||||
|
||||
out.reserve(out.size() + ret->size());
|
||||
for(auto& val : *ret)
|
||||
{
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "lib/rocprofiler-sdk/agent.hpp"
|
||||
#include "lib/rocprofiler-sdk/context/context.hpp"
|
||||
#include "lib/rocprofiler-sdk/counters/dispatch_handlers.hpp"
|
||||
#include "lib/rocprofiler-sdk/counters/id_decode.hpp"
|
||||
#include "lib/rocprofiler-sdk/counters/metrics.hpp"
|
||||
#include "lib/rocprofiler-sdk/counters/tests/hsa_tables.hpp"
|
||||
#include "lib/rocprofiler-sdk/hsa/agent_cache.hpp"
|
||||
@@ -745,8 +746,20 @@ TEST(core, public_api_iterate_agents)
|
||||
auto expected = findDeviceMetrics(agent, {});
|
||||
for(const auto& x : expected)
|
||||
{
|
||||
ASSERT_GT(from_api.count(x.id()), 0);
|
||||
from_api.erase(x.id());
|
||||
// Counter IDs from API now include agent encoding. Extract base metric ID for
|
||||
// comparison.
|
||||
bool found = false;
|
||||
for(auto it = from_api.begin(); it != from_api.end(); ++it)
|
||||
{
|
||||
rocprofiler_counter_id_t counter_id = {.handle = *it};
|
||||
if(counters::get_base_metric_from_counter_id(counter_id) == x.id())
|
||||
{
|
||||
from_api.erase(it);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ASSERT_TRUE(found) << "Expected counter ID " << x.id() << " not found in API results";
|
||||
}
|
||||
EXPECT_TRUE(from_api.empty());
|
||||
}
|
||||
|
||||
@@ -61,12 +61,25 @@ check_dim_pos(rocprofiler_counter_instance_id_t
|
||||
}
|
||||
|
||||
void
|
||||
check_counter_id(rocprofiler_counter_instance_id_t id, uint64_t expected_handle)
|
||||
check_counter_id(rocprofiler_counter_instance_id_t id, uint64_t expected_base_metric)
|
||||
{
|
||||
using namespace rocprofiler::counters;
|
||||
|
||||
rocprofiler_counter_id_t api_id = {.handle = 0};
|
||||
rocprofiler_query_record_counter_id(id, &api_id);
|
||||
EXPECT_EQ(rocprofiler::counters::rec_to_counter_id(id).handle, expected_handle);
|
||||
EXPECT_EQ(rocprofiler::counters::rec_to_counter_id(id).handle, api_id.handle);
|
||||
|
||||
auto reconstructed_id = rec_to_counter_id(id);
|
||||
|
||||
// After our agent encoding changes, rec_to_counter_id() returns a full agent-encoded
|
||||
// counter ID. We need to extract the base metric ID to compare with the expected value.
|
||||
auto reconstructed_base = get_base_metric_from_counter_id(reconstructed_id);
|
||||
auto api_base = get_base_metric_from_counter_id(api_id);
|
||||
|
||||
EXPECT_EQ(reconstructed_base, expected_base_metric);
|
||||
EXPECT_EQ(api_base, expected_base_metric);
|
||||
|
||||
// Both methods should return the same counter ID (including agent encoding)
|
||||
EXPECT_EQ(reconstructed_id.handle, api_id.handle);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@@ -251,7 +264,7 @@ TEST(dimension, block_dim_test)
|
||||
/**
|
||||
* Compare with actual
|
||||
*/
|
||||
auto dims = getBlockDimensions(agent.name(), metric);
|
||||
auto dims = getBlockDimensions(agent.get_rocp_agent()->id, metric);
|
||||
EXPECT_FALSE(dims.empty());
|
||||
EXPECT_EQ(dims.size(), rocp_dims.size());
|
||||
for(const auto& dim : dims)
|
||||
@@ -266,7 +279,7 @@ TEST(dimension, block_dim_test)
|
||||
/**
|
||||
* Check this value exists in the dimension cache
|
||||
*/
|
||||
auto dim_ptr = counters::get_dimension_cache();
|
||||
auto dim_ptr = counters::get_dimension_cache(agent.get_rocp_agent()->id);
|
||||
const auto* dim_cache = rocprofiler::common::get_val(dim_ptr->id_to_dim, metric.id());
|
||||
ASSERT_TRUE(dim_cache);
|
||||
EXPECT_EQ(fmt::format("{}", fmt::join(dims, "|")),
|
||||
@@ -289,7 +302,10 @@ TEST(dimension, block_dim_test)
|
||||
EXPECT_EQ(instance_count, calculated_instance_count);
|
||||
|
||||
/**
|
||||
* Check the public API returns this value
|
||||
* Check the public API returns this value.
|
||||
* Counter IDs now have agent encoding, so rocprofiler_iterate_counter_dimensions()
|
||||
* can extract the agent from the counter ID itself and return agent-specific
|
||||
* dimensions.
|
||||
*/
|
||||
rocprofiler_iterate_counter_dimensions(
|
||||
{.handle = metric.id()},
|
||||
|
||||
+60
-19
@@ -326,12 +326,16 @@ TEST(evaluate_ast, counter_constants)
|
||||
// Check that the value matches agent_t and that its dim/id is set correctly
|
||||
ASSERT_EQ(ptr->size(), 1);
|
||||
EXPECT_EQ(ptr->at(0).counter_value, raw_agent_values[c.name()]);
|
||||
EXPECT_EQ(rocprofiler::counters::rec_to_counter_id(ptr->at(0).id).handle, c.id());
|
||||
EXPECT_EQ(rocprofiler::counters::rec_to_dim_pos(
|
||||
ptr->at(0).id,
|
||||
rocprofiler::counters::rocprofiler_profile_counter_instance_types::
|
||||
ROCPROFILER_DIMENSION_NONE),
|
||||
0);
|
||||
|
||||
// After agent encoding changes, rec_to_counter_id() returns a full agent-encoded ID
|
||||
// Extract and compare just the base metric ID
|
||||
auto reconstructed_id = rocprofiler::counters::rec_to_counter_id(ptr->at(0).id);
|
||||
auto base_metric =
|
||||
rocprofiler::counters::get_base_metric_from_counter_id(reconstructed_id);
|
||||
EXPECT_EQ(base_metric, c.id());
|
||||
|
||||
// Note: With agent encoding, ROCPROFILER_DIMENSION_AGENT is always set,
|
||||
// so we cannot check that ROCPROFILER_DIMENSION_NONE == 0
|
||||
}
|
||||
asts.at("gfx9").at(name).expand_derived(asts.at("gfx9"));
|
||||
std::vector<std::unique_ptr<std::vector<rocprofiler_record_counter_t>>> cache;
|
||||
@@ -340,13 +344,13 @@ TEST(evaluate_ast, counter_constants)
|
||||
EXPECT_FLOAT_EQ(ret->at(0).counter_value, final_computed_values[name]);
|
||||
|
||||
asts.at("gfx9").at(name).set_out_id(*ret);
|
||||
EXPECT_EQ(rocprofiler::counters::rec_to_counter_id(ret->at(0).id).handle,
|
||||
metrics[name].id());
|
||||
EXPECT_EQ(rocprofiler::counters::rec_to_dim_pos(
|
||||
ret->at(0).id,
|
||||
rocprofiler::counters::rocprofiler_profile_counter_instance_types::
|
||||
ROCPROFILER_DIMENSION_NONE),
|
||||
0);
|
||||
// After agent encoding changes, rec_to_counter_id() returns agent-encoded ID
|
||||
// Extract and compare just the base metric ID
|
||||
auto reconstructed_id = rocprofiler::counters::rec_to_counter_id(ret->at(0).id);
|
||||
auto base_metric = rocprofiler::counters::get_base_metric_from_counter_id(reconstructed_id);
|
||||
EXPECT_EQ(base_metric, metrics[name].id());
|
||||
// Note: With agent encoding, ROCPROFILER_DIMENSION_AGENT is always set,
|
||||
// so we cannot check that ROCPROFILER_DIMENSION_NONE == 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -528,7 +532,13 @@ TEST(evaluate_ast, evaluate_simple_counters)
|
||||
for(const auto& v : *ret)
|
||||
{
|
||||
set_counter_in_rec(expected[pos].id, {.handle = metrics[name].id()});
|
||||
EXPECT_EQ(v.id, expected[pos].id);
|
||||
// After agent encoding changes, compare base metrics extracted from counter IDs
|
||||
auto v_counter_id = rocprofiler::counters::rec_to_counter_id(v.id);
|
||||
auto expected_counter_id = rocprofiler::counters::rec_to_counter_id(expected[pos].id);
|
||||
auto v_base = rocprofiler::counters::get_base_metric_from_counter_id(v_counter_id);
|
||||
auto expected_base =
|
||||
rocprofiler::counters::get_base_metric_from_counter_id(expected_counter_id);
|
||||
EXPECT_EQ(v_base, expected_base);
|
||||
EXPECT_FLOAT_EQ(v.counter_value, expected[pos].counter_value);
|
||||
pos++;
|
||||
}
|
||||
@@ -650,7 +660,13 @@ run_reduce_test(
|
||||
for(const auto& v : *ret)
|
||||
{
|
||||
set_counter_in_rec(expected[pos].id, {.handle = metrics[name].id()});
|
||||
EXPECT_EQ(v.id, expected[pos].id);
|
||||
// After agent encoding changes, compare base metrics extracted from counter IDs
|
||||
auto v_counter_id = rocprofiler::counters::rec_to_counter_id(v.id);
|
||||
auto expected_counter_id = rocprofiler::counters::rec_to_counter_id(expected[pos].id);
|
||||
auto v_base = rocprofiler::counters::get_base_metric_from_counter_id(v_counter_id);
|
||||
auto expected_base =
|
||||
rocprofiler::counters::get_base_metric_from_counter_id(expected_counter_id);
|
||||
EXPECT_EQ(v_base, expected_base);
|
||||
EXPECT_FLOAT_EQ(v.counter_value, expected[pos].counter_value);
|
||||
pos++;
|
||||
}
|
||||
@@ -1155,7 +1171,14 @@ TEST(evaluate_ast, evaluate_mixed_counters)
|
||||
for(const auto& v : *ret)
|
||||
{
|
||||
set_counter_in_rec(expected.at(pos).id, {.handle = metrics[name].id()});
|
||||
EXPECT_EQ(v.id, expected.at(pos).id);
|
||||
// After agent encoding changes, compare base metrics extracted from counter IDs
|
||||
auto v_counter_id = rocprofiler::counters::rec_to_counter_id(v.id);
|
||||
auto expected_counter_id =
|
||||
rocprofiler::counters::rec_to_counter_id(expected.at(pos).id);
|
||||
auto v_base = rocprofiler::counters::get_base_metric_from_counter_id(v_counter_id);
|
||||
auto expected_base =
|
||||
rocprofiler::counters::get_base_metric_from_counter_id(expected_counter_id);
|
||||
EXPECT_EQ(v_base, expected_base);
|
||||
EXPECT_FLOAT_EQ(v.counter_value, expected.at(pos).counter_value);
|
||||
pos++;
|
||||
}
|
||||
@@ -1253,7 +1276,13 @@ TEST(evaluate_ast, derived_counter_reduction)
|
||||
for(const auto& v : *ret)
|
||||
{
|
||||
set_counter_in_rec(expected[pos].id, {.handle = metrics[name].id()});
|
||||
EXPECT_EQ(v.id, expected[pos].id);
|
||||
// After agent encoding changes, compare base metrics extracted from counter IDs
|
||||
auto v_counter_id = rocprofiler::counters::rec_to_counter_id(v.id);
|
||||
auto expected_counter_id = rocprofiler::counters::rec_to_counter_id(expected[pos].id);
|
||||
auto v_base = rocprofiler::counters::get_base_metric_from_counter_id(v_counter_id);
|
||||
auto expected_base =
|
||||
rocprofiler::counters::get_base_metric_from_counter_id(expected_counter_id);
|
||||
EXPECT_EQ(v_base, expected_base);
|
||||
EXPECT_FLOAT_EQ(v.counter_value, expected[pos].counter_value);
|
||||
pos++;
|
||||
}
|
||||
@@ -1382,7 +1411,13 @@ TEST(evatuate_ast, evaluate_select)
|
||||
for(const auto& v : *ret)
|
||||
{
|
||||
set_counter_in_rec(expected[pos].id, {.handle = metrics[name].id()});
|
||||
EXPECT_EQ(v.id, expected[pos].id);
|
||||
// After agent encoding changes, compare base metrics extracted from counter IDs
|
||||
auto v_counter_id = rocprofiler::counters::rec_to_counter_id(v.id);
|
||||
auto expected_counter_id = rocprofiler::counters::rec_to_counter_id(expected[pos].id);
|
||||
auto v_base = rocprofiler::counters::get_base_metric_from_counter_id(v_counter_id);
|
||||
auto expected_base =
|
||||
rocprofiler::counters::get_base_metric_from_counter_id(expected_counter_id);
|
||||
EXPECT_EQ(v_base, expected_base);
|
||||
EXPECT_FLOAT_EQ(v.counter_value, expected[pos].counter_value);
|
||||
pos++;
|
||||
}
|
||||
@@ -1520,7 +1555,13 @@ TEST(evaluate_ast, counter_reduction_dimension)
|
||||
for(const auto& v : *ret)
|
||||
{
|
||||
set_counter_in_rec(expected[pos].id, {.handle = metrics[name].id()});
|
||||
EXPECT_EQ(v.id, expected[pos].id);
|
||||
// After agent encoding changes, compare base metrics extracted from counter IDs
|
||||
auto v_counter_id = rocprofiler::counters::rec_to_counter_id(v.id);
|
||||
auto expected_counter_id = rocprofiler::counters::rec_to_counter_id(expected[pos].id);
|
||||
auto v_base = rocprofiler::counters::get_base_metric_from_counter_id(v_counter_id);
|
||||
auto expected_base =
|
||||
rocprofiler::counters::get_base_metric_from_counter_id(expected_counter_id);
|
||||
EXPECT_EQ(v_base, expected_base);
|
||||
EXPECT_FLOAT_EQ(v.counter_value, expected[pos].counter_value);
|
||||
pos++;
|
||||
}
|
||||
|
||||
+21
-17
@@ -223,13 +223,17 @@ TEST(metrics, check_public_api_query)
|
||||
{
|
||||
rocprofiler_counter_info_v1_t info;
|
||||
|
||||
auto dim_ptr = rocprofiler::counters::get_dimension_cache();
|
||||
|
||||
const auto* dims = rocprofiler::common::get_val(dim_ptr->id_to_dim, metric.id());
|
||||
ASSERT_TRUE(dims);
|
||||
// Note: Direct dimension cache access requires an agent_id, which is not available
|
||||
// in this unit test. The API call below handles agent lookup internally.
|
||||
// auto dim_ptr = rocprofiler::counters::get_dimension_cache(agent_id);
|
||||
// const auto* dims = rocprofiler::common::get_val(dim_ptr->id_to_dim, metric.id());
|
||||
|
||||
auto status = rocprofiler_query_counter_info(
|
||||
{.handle = id}, ROCPROFILER_COUNTER_INFO_VERSION_1, static_cast<void*>(&info));
|
||||
|
||||
// Skip dimension checks if no agent is found (happens in unit tests without GPU)
|
||||
if(status == ROCPROFILER_STATUS_ERROR_AGENT_NOT_FOUND) continue;
|
||||
|
||||
ASSERT_EQ(status, ROCPROFILER_STATUS_SUCCESS);
|
||||
EXPECT_EQ(std::string(info.name ? info.name : ""), metric.name());
|
||||
EXPECT_EQ(std::string(info.block ? info.block : ""), metric.block());
|
||||
@@ -237,23 +241,21 @@ TEST(metrics, check_public_api_query)
|
||||
EXPECT_EQ(info.is_derived, !metric.expression().empty());
|
||||
EXPECT_EQ(std::string(info.description ? info.description : ""), metric.description());
|
||||
|
||||
EXPECT_EQ(info.dimensions_count, dims->size());
|
||||
// Dimensions are now verified through the API call above
|
||||
for(size_t i = 0; i < info.dimensions_count; i++)
|
||||
{
|
||||
const auto& dim = dims->at(i);
|
||||
EXPECT_EQ(dim.size(), info.dimensions[i]->instance_size);
|
||||
EXPECT_EQ(dim.type(), info.dimensions[i]->id);
|
||||
EXPECT_EQ(std::string(info.dimensions[i]->name), dim.name());
|
||||
EXPECT_GT(info.dimensions[i]->instance_size, 0u);
|
||||
EXPECT_TRUE(info.dimensions[i]->name != nullptr);
|
||||
}
|
||||
|
||||
size_t instance_count = 0;
|
||||
// Checks the equality with the old rocprofiler_query_counter_instance_count
|
||||
for(const auto& metric_dim : *dims)
|
||||
// Calculate expected instance count from API-returned dimensions
|
||||
for(size_t i = 0; i < info.dimensions_count; i++)
|
||||
{
|
||||
if(instance_count == 0)
|
||||
instance_count = metric_dim.size();
|
||||
else if(metric_dim.size() > 0)
|
||||
instance_count = metric_dim.size() * instance_count;
|
||||
instance_count = info.dimensions[i]->instance_size;
|
||||
else if(info.dimensions[i]->instance_size > 0)
|
||||
instance_count = info.dimensions[i]->instance_size * instance_count;
|
||||
}
|
||||
|
||||
EXPECT_EQ(info.dimensions_instances_count, instance_count);
|
||||
@@ -266,12 +268,14 @@ TEST(metrics, check_public_api_query)
|
||||
rocprofiler::counters::rec_to_counter_id(info.dimensions_instances[i]->instance_id)
|
||||
.handle,
|
||||
metric.id());
|
||||
for(const auto& metric_dim : *dims)
|
||||
for(size_t j = 0; j < info.dimensions_count; j++)
|
||||
{
|
||||
dim_ids.push_back(rocprofiler::counters::rec_to_dim_pos(
|
||||
info.dimensions_instances[i]->instance_id, metric_dim.type()));
|
||||
info.dimensions_instances[i]->instance_id,
|
||||
static_cast<rocprofiler::counters::rocprofiler_profile_counter_instance_types>(
|
||||
info.dimensions[j]->id)));
|
||||
}
|
||||
// Ensure that the premutation is unique
|
||||
// Ensure that the permutation is unique
|
||||
ASSERT_EQ(dim_permutations.insert(dim_ids).second, true);
|
||||
}
|
||||
ASSERT_EQ(instance_count, dim_permutations.size());
|
||||
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2023-2025 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "lib/common/utility.hpp"
|
||||
#include "lib/rocprofiler-sdk/counters/metrics.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace rocprofiler
|
||||
{
|
||||
namespace counters
|
||||
{
|
||||
/**
|
||||
* Test helper: Get metrics by architecture name without agent encoding.
|
||||
* This function is for internal testing purposes only and should not be used in production code.
|
||||
* Returns metrics with base IDs only (no agent-specific encoding).
|
||||
*/
|
||||
inline std::vector<Metric>
|
||||
getMetricsForAgent(const std::string& agent_arch)
|
||||
{
|
||||
auto mets = loadMetrics();
|
||||
if(const auto* metric_ptr = rocprofiler::common::get_val(mets->arch_to_metric, agent_arch))
|
||||
{
|
||||
return *metric_ptr;
|
||||
}
|
||||
return std::vector<Metric>{};
|
||||
}
|
||||
|
||||
} // namespace counters
|
||||
} // namespace rocprofiler
|
||||
@@ -40,6 +40,7 @@
|
||||
#include <rocprofiler-sdk/fwd.h>
|
||||
#include <rocprofiler-sdk/hsa/api_id.h>
|
||||
#include <rocprofiler-sdk/hsa/table_id.h>
|
||||
#include <rocprofiler-sdk/cxx/constants.hpp>
|
||||
|
||||
#include <glog/logging.h>
|
||||
#include <hsa/amd_hsa_signal.h>
|
||||
@@ -142,8 +143,6 @@ context_filter(const context::context* ctx)
|
||||
return (has_buffered || has_callback);
|
||||
}
|
||||
|
||||
constexpr auto null_rocp_agent_id = rocprofiler_agent_id_t{.handle = 0};
|
||||
|
||||
struct async_copy_data
|
||||
{
|
||||
using timestamp_t = rocprofiler_timestamp_t;
|
||||
@@ -153,8 +152,8 @@ struct async_copy_data
|
||||
hsa_signal_t orig_signal = {};
|
||||
hsa_signal_t rocp_signal = {};
|
||||
rocprofiler_thread_id_t tid = common::get_tid();
|
||||
rocprofiler_agent_id_t dst_agent = null_rocp_agent_id;
|
||||
rocprofiler_agent_id_t src_agent = null_rocp_agent_id;
|
||||
rocprofiler_agent_id_t dst_agent = sdk::null_agent_id;
|
||||
rocprofiler_agent_id_t src_agent = sdk::null_agent_id;
|
||||
rocprofiler_address_t dst_address = {.value = 0};
|
||||
rocprofiler_address_t src_address = {.value = 0};
|
||||
rocprofiler_memory_copy_operation_t direction = ROCPROFILER_MEMORY_COPY_NONE;
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include <rocprofiler-sdk/fwd.h>
|
||||
#include <rocprofiler-sdk/hsa/api_id.h>
|
||||
#include <rocprofiler-sdk/hsa/table_id.h>
|
||||
#include <rocprofiler-sdk/cxx/constants.hpp>
|
||||
|
||||
#include <glog/logging.h>
|
||||
#include <hsa/amd_hsa_signal.h>
|
||||
@@ -324,8 +325,6 @@ get_next_dispatch()
|
||||
return _v;
|
||||
}
|
||||
|
||||
constexpr auto null_rocp_agent_id = rocprofiler_agent_id_t{.handle = 0};
|
||||
|
||||
struct memory_allocation_data
|
||||
{
|
||||
using timestamp_t = rocprofiler_timestamp_t;
|
||||
@@ -333,7 +332,7 @@ struct memory_allocation_data
|
||||
using buffered_data_t = rocprofiler_buffer_tracing_memory_allocation_record_t;
|
||||
|
||||
rocprofiler_thread_id_t tid = common::get_tid();
|
||||
rocprofiler_agent_id_t agent = null_rocp_agent_id;
|
||||
rocprofiler_agent_id_t agent = sdk::null_agent_id;
|
||||
uint64_t size_allocated = 0;
|
||||
rocprofiler_address_t address = {.handle = 0};
|
||||
uint64_t start_ts = 0;
|
||||
@@ -414,7 +413,7 @@ get_agent(T val, IterateFunc iterate_func, CallbackFunc callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
return existing.count(val) == 0 ? null_rocp_agent_id : existing.at(val);
|
||||
return existing.count(val) == 0 ? sdk::null_agent_id : existing.at(val);
|
||||
}
|
||||
|
||||
rocprofiler_address_t
|
||||
|
||||
+2
-1
@@ -26,6 +26,7 @@
|
||||
#include "lib/rocprofiler-sdk/context/context.hpp"
|
||||
#include "lib/rocprofiler-sdk/counters/metrics.hpp"
|
||||
#include "lib/rocprofiler-sdk/counters/tests/hsa_tables.hpp"
|
||||
#include "lib/rocprofiler-sdk/counters/tests/metrics_test_helpers.hpp"
|
||||
#include "lib/rocprofiler-sdk/hsa/agent_cache.hpp"
|
||||
#include "lib/rocprofiler-sdk/hsa/hsa.hpp"
|
||||
#include "lib/rocprofiler-sdk/hsa/queue.hpp"
|
||||
@@ -286,7 +287,7 @@ query_available_agents(rocprofiler_agent_version_t /* version */,
|
||||
params.push_back({ROCPROFILER_THREAD_TRACE_PARAMETER_NO_DETAIL, {0}});
|
||||
|
||||
{
|
||||
auto metrics = rocprofiler::counters::getMetricsForAgent("gfx90a");
|
||||
auto metrics = rocprofiler::counters::getMetricsForAgent(agent);
|
||||
|
||||
rocprofiler_thread_trace_parameter_t att_param;
|
||||
att_param.type = ROCPROFILER_THREAD_TRACE_PARAMETER_PERFCOUNTER;
|
||||
|
||||
@@ -64,6 +64,9 @@ if(attdecoder_FOUND)
|
||||
set(IS_DISABLED OFF)
|
||||
set(COMMON_PARAMS --att-library-path ${attdecoder_LIB_DIR} ${COMMON_PARAMS_NO_LIB})
|
||||
endif()
|
||||
if(ROCPROFILER_DISABLE_UNSTABLE_CTESTS)
|
||||
set(IS_DISABLED ON)
|
||||
endif()
|
||||
|
||||
# hsa multiqueue dependency test with lib path
|
||||
add_test(
|
||||
|
||||
@@ -57,9 +57,16 @@ add_test(NAME thread-trace-api-single-test
|
||||
|
||||
set_tests_properties(
|
||||
thread-trace-api-single-test
|
||||
PROPERTIES TIMEOUT 10 LABELS "integration-tests" ENVIRONMENT
|
||||
"${ROCPROFILER_MEMCHECK_PRELOAD_ENV}" FAIL_REGULAR_EXPRESSION
|
||||
"${ROCPROFILER_DEFAULT_FAIL_REGEX}")
|
||||
PROPERTIES TIMEOUT
|
||||
10
|
||||
LABELS
|
||||
"integration-tests"
|
||||
ENVIRONMENT
|
||||
"${ROCPROFILER_MEMCHECK_PRELOAD_ENV}"
|
||||
FAIL_REGULAR_EXPRESSION
|
||||
"${ROCPROFILER_DEFAULT_FAIL_REGEX}"
|
||||
DISABLED
|
||||
${ROCPROFILER_DISABLE_UNSTABLE_CTESTS})
|
||||
|
||||
# Multi dispatch test
|
||||
add_executable(thread-trace-api-multi-test)
|
||||
@@ -76,9 +83,16 @@ add_test(NAME thread-trace-api-multi-test
|
||||
|
||||
set_tests_properties(
|
||||
thread-trace-api-multi-test
|
||||
PROPERTIES TIMEOUT 10 LABELS "integration-tests" ENVIRONMENT
|
||||
"${ROCPROFILER_MEMCHECK_PRELOAD_ENV}" FAIL_REGULAR_EXPRESSION
|
||||
"${ROCPROFILER_DEFAULT_FAIL_REGEX}")
|
||||
PROPERTIES TIMEOUT
|
||||
10
|
||||
LABELS
|
||||
"integration-tests"
|
||||
ENVIRONMENT
|
||||
"${ROCPROFILER_MEMCHECK_PRELOAD_ENV}"
|
||||
FAIL_REGULAR_EXPRESSION
|
||||
"${ROCPROFILER_DEFAULT_FAIL_REGEX}"
|
||||
DISABLED
|
||||
${ROCPROFILER_DISABLE_UNSTABLE_CTESTS})
|
||||
|
||||
# Agent profiling test
|
||||
add_executable(thread-trace-api-agent-test)
|
||||
@@ -94,9 +108,16 @@ add_test(NAME thread-trace-api-agent-test
|
||||
|
||||
set_tests_properties(
|
||||
thread-trace-api-agent-test
|
||||
PROPERTIES TIMEOUT 10 LABELS "integration-tests" ENVIRONMENT
|
||||
"${ROCPROFILER_MEMCHECK_PRELOAD_ENV}" FAIL_REGULAR_EXPRESSION
|
||||
"${ROCPROFILER_DEFAULT_FAIL_REGEX}")
|
||||
PROPERTIES TIMEOUT
|
||||
10
|
||||
LABELS
|
||||
"integration-tests"
|
||||
ENVIRONMENT
|
||||
"${ROCPROFILER_MEMCHECK_PRELOAD_ENV}"
|
||||
FAIL_REGULAR_EXPRESSION
|
||||
"${ROCPROFILER_DEFAULT_FAIL_REGEX}"
|
||||
DISABLED
|
||||
${ROCPROFILER_DISABLE_UNSTABLE_CTESTS})
|
||||
|
||||
# Test large buffer sizes. 5120 == 5GB
|
||||
add_test(NAME thread-trace-api-large-buffer-test
|
||||
|
||||
Fai riferimento in un nuovo problema
Block a user