// 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/logging.hpp" #include "lib/common/utility.hpp" #include "lib/rocprofiler-sdk/counters/id_decode.hpp" #include #include #include #include #include #include #include #include #include #include namespace rocprofiler { namespace counters { enum NodeType { NONE = 0, ADDITION_NODE, DIVIDE_NODE, MULTIPLY_NODE, NUMBER_NODE, RANGE_NODE, REDUCE_NODE, REFERENCE_NODE, SELECT_NODE, SUBTRACTION_NODE, CONSTANT_NODE, ACCUMULATE_NODE }; enum class ACCUMULATE_OP_TYPE { NONE = 0, LOW_RESOLUTION, HIGH_RESOLUTION }; struct LinkedList { std::string name; int data{-1}; std::string range_data; LinkedList* next{nullptr}; LinkedList(const char* v, LinkedList* next_node) : name(std::string{CHECK_NOTNULL(v)}) , next(next_node) {} LinkedList(const char* v, int d, LinkedList* next_node) : name(std::string{CHECK_NOTNULL(v)}) , data(d) , next(next_node) {} LinkedList(const char* v, const char* r, LinkedList* next_node) : name(std::string{CHECK_NOTNULL(v)}) , range_data(std::string{CHECK_NOTNULL(r)}) , next(next_node) {} }; struct RawAST { // Node type NodeType type{NONE}; // Operation to perform on the counter set std::string reduce_op{}; ACCUMULATE_OP_TYPE accumulate_op{ACCUMULATE_OP_TYPE::NONE}; // Stores either the name or digit dependening on whether this // is a name or number std::variant value{std::monostate{}}; // Counter set of ASTs needed to compute this counter. // Operation is applied to all counters in this set. std::vector counter_set; // Dimension set to remove dimensions (such as shader engine) // from the result. std::unordered_set reduce_dimension_set; // Dimension set to select certain dimensions from the result std::map select_dimension_map; // Range restriction on this node RawAST* range{nullptr}; ~RawAST() { auto deleteVec = [](auto& vec) { for(auto val : vec) { delete val; } }; deleteVec(counter_set); delete range; } // Constructors for raw value types RawAST(NodeType t, const char* v) : type(t) , value(std::string{CHECK_NOTNULL(v)}) {} RawAST(NodeType t, int64_t v) : type(t) , value(v) {} static const auto& get_dim_map() { static const auto dim_map = []() { std::map out; const auto& dims = dimension_map(); for(const auto& [id, name] : dims) { out.emplace(name, id); } return out; }(); return dim_map; } // Reduce operation constructor. Counter is the counter AST // to use for the reduce op, op is how to reduce (i.e. SUM,AVG,etc), // dimensions contains the set of dimensions which we want to keep // in the result. Dimensions not specified are all reduced according to op RawAST(NodeType t, RawAST* counter, const char* op, LinkedList* dimensions) : type(t) , reduce_op(CHECK_NOTNULL(op)) , counter_set({counter}) { CHECK_EQ(t, REDUCE_NODE); if(dimensions) { while(dimensions) { const rocprofiler_profile_counter_instance_types* dim = rocprofiler::common::get_val(get_dim_map(), std::string{dimensions->name}); if(!dim) { throw std::runtime_error( fmt::format("Unknown Dimension - {}", dimensions->name)); } reduce_dimension_set.insert(*dim); LinkedList* current = dimensions; dimensions = dimensions->next; delete current; } } } RawAST(NodeType t, const char* v, const char* op) : type(t) , value(std::string{CHECK_NOTNULL(v)}) { CHECK_NOTNULL(op); static std::unordered_map map = { {"NONE", ACCUMULATE_OP_TYPE::NONE}, {"LOW_RES", ACCUMULATE_OP_TYPE::LOW_RESOLUTION}, {"HIGH_RES", ACCUMULATE_OP_TYPE::HIGH_RESOLUTION}, }; accumulate_op = map.at(static_cast(op)); CHECK_EQ(t, ACCUMULATE_NODE); } // Select operation constructor. Counter is the counter AST // to use for the reduce op, refs is the reference set AST. // dimensions contains the mapping for selecting dimensions // (XCC=1,SE=2,...) RawAST(NodeType t, RawAST* counter, LinkedList* dimensions) : type(t) , counter_set({counter}) { if(dimensions) { while(dimensions) { const rocprofiler_profile_counter_instance_types* dim = rocprofiler::common::get_val(get_dim_map(), dimensions->name); if(!dim) { throw std::runtime_error( fmt::format("Unknown Dimension - {}", dimensions->name)); } select_dimension_map.insert({*dim, (dimensions->data != -1) ? std::to_string(dimensions->data) : dimensions->range_data}); LinkedList* current = dimensions; dimensions = dimensions->next; delete current; } } else { ROCP_ERROR << "select_dimension_set creation failed."; } } RawAST(NodeType t, std::vector c) : type(t) , counter_set(std::move(c)) {} }; } // namespace counters } // namespace rocprofiler namespace fmt { // fmt::format support for RawAST template <> struct formatter { template constexpr auto parse(ParseContext& ctx) { return ctx.begin(); } template auto format(rocprofiler::counters::RawAST const& ast, Ctx& ctx) const { static const std::map NodeTypeToString = { {rocprofiler::counters::NONE, "NONE"}, {rocprofiler::counters::ADDITION_NODE, "ADDITION_NODE"}, {rocprofiler::counters::DIVIDE_NODE, "DIVIDE_NODE"}, {rocprofiler::counters::MULTIPLY_NODE, "MULTIPLY_NODE"}, {rocprofiler::counters::NUMBER_NODE, "NUMBER_NODE"}, {rocprofiler::counters::RANGE_NODE, "RANGE_NODE"}, {rocprofiler::counters::ACCUMULATE_NODE, "ACCUMULATE_NODE"}, {rocprofiler::counters::REDUCE_NODE, "REDUCE_NODE"}, {rocprofiler::counters::REFERENCE_NODE, "REFERENCE_NODE"}, {rocprofiler::counters::SELECT_NODE, "SELECT_NODE"}, {rocprofiler::counters::SUBTRACTION_NODE, "SUBTRACTION_NODE"}, }; static std::unordered_map AccumulateTypeToString = { {rocprofiler::counters::ACCUMULATE_OP_TYPE::NONE, "NONE"}, {rocprofiler::counters::ACCUMULATE_OP_TYPE::HIGH_RESOLUTION, "HIGH_RES"}, {rocprofiler::counters::ACCUMULATE_OP_TYPE::LOW_RESOLUTION, "LOW_RES"}, }; auto out = fmt::format_to(ctx.out(), "{{\"Type\":\"{}\", \"REDUCE_OP\":\"{}\", \"ACCUMULATE_OP\":\"{}\",", NodeTypeToString.at(ast.type), ast.reduce_op, AccumulateTypeToString.at(ast.accumulate_op)); if(const auto* string_val = std::get_if(&ast.value)) { out = fmt::format_to(out, " \"Value\":\"{}\",", *string_val); } else if(const auto* int_val = std::get_if(&ast.value)) { out = fmt::format_to(out, " \"Value\":{},", *int_val); } if(ast.range) { out = fmt::format_to(out, " \"Range\":{},", *ast.range); } static const std::map SelectDimensionTypeToString = { {rocprofiler::counters::rocprofiler_profile_counter_instance_types:: ROCPROFILER_DIMENSION_NONE, "DIMENSION_NONE"}, {rocprofiler::counters::rocprofiler_profile_counter_instance_types:: ROCPROFILER_DIMENSION_XCC, "DIMENSION_XCC"}, {rocprofiler::counters::rocprofiler_profile_counter_instance_types:: ROCPROFILER_DIMENSION_AID, "DIMENSION_AID"}, {rocprofiler::counters::rocprofiler_profile_counter_instance_types:: ROCPROFILER_DIMENSION_SHADER_ENGINE, "DIMENSION_SHADER_ENGINE"}, {rocprofiler::counters::rocprofiler_profile_counter_instance_types:: ROCPROFILER_DIMENSION_AGENT, "DIMENSION_AGENT"}, {rocprofiler::counters::rocprofiler_profile_counter_instance_types:: ROCPROFILER_DIMENSION_SHADER_ARRAY, "DIMENSION_SHADER_ARRAY"}, {rocprofiler::counters::rocprofiler_profile_counter_instance_types:: ROCPROFILER_DIMENSION_WGP, "DIMENSION_WGP"}, {rocprofiler::counters::rocprofiler_profile_counter_instance_types:: ROCPROFILER_DIMENSION_INSTANCE, "DIMENSION_INSTANCE"}, {rocprofiler::counters::rocprofiler_profile_counter_instance_types:: ROCPROFILER_DIMENSION_LAST, "DIMENSION_LAST"}, }; out = fmt::format_to(out, " \"Counter_Set\":["); for(const auto& ref : ast.counter_set) { out = fmt::format_to( out, "{}{}", *CHECK_NOTNULL(ref), ref == ast.counter_set.back() ? "" : ","); } out = fmt::format_to(out, "], \"Reduce_Dimension_Set\":["); size_t ReduceSetIndex = 0; for(const auto& ref : ast.reduce_dimension_set) { out = fmt::format_to(out, "\"{}\"{}", static_cast(ref), ++ReduceSetIndex == ast.reduce_dimension_set.size() ? "" : ","); } out = fmt::format_to(out, "], \"Select_Dimension_Map\":["); size_t SelectSetIndex = 0; for(const auto& [type, val] : ast.select_dimension_map) { out = fmt::format_to(out, "\"{}:\"{}\"\"{}", SelectDimensionTypeToString.at(type), val, ++SelectSetIndex == ast.select_dimension_map.size() ? "" : ","); } return fmt::format_to(out, "]}}"); } }; } // namespace fmt