-
Notifications
You must be signed in to change notification settings - Fork 101
Fix CPX mode crash by removing agent encoding from counter IDs #2522
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -88,33 +88,40 @@ 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 | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| namespace counters = ::rocprofiler::counters; | ||||||||||||||||||||||||||||||||||||||||
| namespace common = ::rocprofiler::common; | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| namespace | ||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||
| // Global mapping from base_metric_id to agent_id for counters | ||||||||||||||||||||||||||||||||||||||||
| // This replaces the removed agent encoding in counter IDs | ||||||||||||||||||||||||||||||||||||||||
| // Populated when rocprofiler_iterate_agent_supported_counters() is called | ||||||||||||||||||||||||||||||||||||||||
| std::unordered_map<uint64_t, rocprofiler_agent_id_t>& | ||||||||||||||||||||||||||||||||||||||||
| get_counter_agent_map() | ||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||
| static auto* map = new std::unordered_map<uint64_t, rocprofiler_agent_id_t>{}; | ||||||||||||||||||||||||||||||||||||||||
| return *map; | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| // Helper to get agent_id for a counter_id (replaces get_agent_id_from_counter_id) | ||||||||||||||||||||||||||||||||||||||||
| rocprofiler_agent_id_t | ||||||||||||||||||||||||||||||||||||||||
| get_agent_for_counter(rocprofiler_counter_id_t counter_id) | ||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||
| auto base_metric_id = counters::get_base_metric_from_counter_id(counter_id); | ||||||||||||||||||||||||||||||||||||||||
| auto& map = get_counter_agent_map(); | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| if(auto it = map.find(base_metric_id); it != map.end()) | ||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||
| return it->second; | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+115
to
+120
|
||||||||||||||||||||||||||||||||||||||||
| if(auto it = map.find(base_metric_id); it != map.end()) | |
| { | |
| return it->second; | |
| } | |
| if(auto it = map.find(base_metric_id); it != map.end()) | |
| { | |
| return it->second; | |
| } |
Copilot
AI
Jan 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This mapping assumes each metric ID uniquely identifies an agent, but metric IDs are architecture-based. When this function is called for multiple agents with the same architecture (e.g., two gfx90a GPUs), the loop will overwrite the mapping for each metric_id, storing only the last agent. This breaks any subsequent calls to rocprofiler_query_counter_info or rocprofiler_iterate_counter_dimensions, which will retrieve the wrong agent information for counters from earlier agents with the same architecture.
| // Store mapping from base metric ID to agent for later lookup | |
| counter_agent_map[metric.id()] = agent_id; | |
| // Store mapping from base metric ID to agent for later lookup. | |
| // Avoid overwriting an existing mapping when multiple agents share | |
| // the same architecture-based metric ID. | |
| if(counter_agent_map.find(metric.id()) == counter_agent_map.end()) | |
| { | |
| counter_agent_map[metric.id()] = agent_id; | |
| } |
Copilot
AI
Jan 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lines 387 and 390 contain trailing whitespace. Consider removing it to maintain code cleanliness and avoid unnecessary diff noise in version control.
| // Store mapping from base metric ID to agent for later lookup | |
| counter_agent_map[metric.id()] = agent_id; | |
| // Store mapping from base metric ID to agent for later lookup | |
| counter_agent_map[metric.id()] = agent_id; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The global mapping from base_metric_id to agent_id has a critical design flaw: when multiple agents share the same architecture (e.g., two GPUs with gfx90a), they will have identical metric IDs. When rocprofiler_iterate_agent_supported_counters is called for each agent, the second call will overwrite the mapping from the first call, causing get_agent_for_counter to always return the last agent that was iterated. This breaks multi-GPU systems where agents share the same architecture.
Additionally, this unordered_map is not thread-safe. Concurrent writes from multiple threads calling rocprofiler_iterate_agent_supported_counters or concurrent read/write access will cause undefined behavior. Consider using a Synchronized wrapper like the pattern at line 67, or using a different approach that doesn't rely on a single global agent per metric ID (since metric IDs are architecture-based, not agent-specific).