From 1a369af8fa6f60fb5a3e2ecba8060d0e8e46b1c3 Mon Sep 17 00:00:00 2001 From: venkat1361 Date: Mon, 11 Nov 2024 03:44:22 -0600 Subject: [PATCH] SWDEV-477244: Select() Expression Dimension Support (#1091) * add support for select function in derived counters * formatting * renaming select dims variable name from set to map * format * Update doc with select() for dimensions * use : for defining range of values in select dims * - update dimension for metric after select. - make sure to raise runtime error if user provides range for a dimension. * use map instead of unordered_map for select dim info * new line EOF * fix bug: select() operator. * Update evaluate_ast.cpp format * added a check for dim value exceeds max. * Update source/lib/rocprofiler-sdk/counters/evaluate_ast.cpp Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update source/lib/rocprofiler-sdk/counters/evaluate_ast.cpp Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * updated doc with data example for select operation. * changelog.md * Update CHANGELOG.md --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> [ROCm/rocprofiler-sdk commit: cc4811d27d29595c072e28552643542d1b634bac] --- projects/rocprofiler-sdk/CHANGELOG.md | 11 ++ .../counter_collection_services.md | 45 ++++++ .../rocprofiler-sdk/counters/evaluate_ast.cpp | 103 +++++++++++++- .../rocprofiler-sdk/counters/evaluate_ast.hpp | 24 ++-- .../counters/tests/evaluate_ast_test.cpp | 133 ++++++++++++++++++ 5 files changed, 302 insertions(+), 14 deletions(-) diff --git a/projects/rocprofiler-sdk/CHANGELOG.md b/projects/rocprofiler-sdk/CHANGELOG.md index b0b1670c12..9c5bb695f0 100644 --- a/projects/rocprofiler-sdk/CHANGELOG.md +++ b/projects/rocprofiler-sdk/CHANGELOG.md @@ -136,3 +136,14 @@ Full documentation for ROCprofiler-SDK is available at [rocm.docs.amd.com/projec - Removed gfx8 metric definitions - Removed `rocprofv3` installation to sbin directory + +## ROCprofiler-SDK 0.5.0 for ROCm release 6.4 + +### Added + +- Added support for select() operation in counter expression. +### Changed + +### Resolved issues + +### Removed diff --git a/projects/rocprofiler-sdk/source/docs/api-reference/counter_collection_services.md b/projects/rocprofiler-sdk/source/docs/api-reference/counter_collection_services.md index 0895939a71..1b89d7f152 100644 --- a/projects/rocprofiler-sdk/source/docs/api-reference/counter_collection_services.md +++ b/projects/rocprofiler-sdk/source/docs/api-reference/counter_collection_services.md @@ -290,6 +290,51 @@ Expression: 100*reduce(GL2C_HIT,sum)/(reduce(GL2C_HIT,sum)+reduce(GL2C_MISS,sum) The reduce function reduces counter values across all dimensions such as shader engine, SIMD, and so on, to produce a single output value. This helps to collect and compare values across the entire device. Here are the common reduction operations: +### Select Function + +```yaml +expression: select(Y, [DIMENSION_XCC=[0],DIMENSION_SHADER_ENGINE=[2]]) +``` + +select() only returns counter values which match the dimension indexes provided by the user in expression. This operation is to allow a user to state they only want to select specific dimensions index. Supported dimensions include ```DIMENSION_XCC, DIMENSION_AID, DIMENSION_SHADER_ENGINE, DIMENSION_AGENT, DIMENSION_SHADER_ARRAY, DIMENSION_WGP, DIMENSION_INSTANCE```. For example ``select(Y, [DIMENSION_XCC=[0],DIMENSION_SHADER_ENGINE=[2]])`` gives counter values which are from DIMENSION_XCC= 0 and DIMENSION_SHADER_ENGINE= 2 for Y Metric. + +Let's say Y has XCC, SHADER_ENGINE(SE), WGP dimensions with sizes 2, 4, 4 respectively. + +Raw Counter Data in 3D space: + +#### XCC[0]: +| |WGP[0]|WGP[1]|WGP[2]|WGP[3]| +|-------|------|------|------|------| +| SE[0] | 1 | 2 | 3 | 4 | +| SE[1] | 5 | 6 | 7 | 8 | +| SE[2] | 9 | 10 | 11 | 12 | +| SE[3] | 13 | 14 | 15 | 16 | + +#### XCC[1]: +| |WGP[0]|WGP[1]|WGP[2]|WGP[3]| +|-------|------|------|------|------| +| SE[0] | 17 | 18 | 19 | 20 | +| SE[1] | 21 | 22 | 23 | 24 | +| SE[2] | 25 | 26 | 27 | 28 | +| SE[3] | 29 | 30 | 31 | 32 | + +Selecting at XCC=0 results to 2D space with WGP and SH dimensions, as shown below. + +| |WGP[0]|WGP[1]|WGP[2]|WGP[3]| +|-------|------|------|------|------| +| SE[0] | 1 | 2 | 3 | 4 | +| SE[1] | 5 | 6 | 7 | 8 | +| SE[2] | 9 | 10 | 11 | 12 | +| SE[3] | 13 | 14 | 15 | 16 | + +similarly, for `select(Y, [DIMENSION_XCC=[0],DIMENSION_SHADER_ENGINE=[2]])` results in only WGP dimension with XCC=0 and SE=2. + +| |WGP[0]|WGP[1]|WGP[2]|WGP[3]| +|-------|------|------|------|------| +| | 9 | 10 | 11 | 12 | + +### Accumulate Function + - `sum`: Sums to create a single output. For example, `reduce(GL2C_HIT,sum)` sums all `GL2C_HIT` hardware register values. - `avr`: Calculates the average across all dimensions. - `min`: Selects minimum value across all dimensions. diff --git a/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/counters/evaluate_ast.cpp b/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/counters/evaluate_ast.cpp index 8aa57f5537..69b41f8448 100644 --- a/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/counters/evaluate_ast.cpp +++ b/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/counters/evaluate_ast.cpp @@ -22,10 +22,14 @@ #include "lib/rocprofiler-sdk/counters/evaluate_ast.hpp" +#include +#include #include #include #include #include +#include +#include #include #include @@ -33,7 +37,9 @@ #include "lib/common/utility.hpp" #include "lib/rocprofiler-sdk/counters/dimensions.hpp" +#include "lib/rocprofiler-sdk/counters/id_decode.hpp" #include "lib/rocprofiler-sdk/counters/parser/reader.hpp" +#include "rocprofiler-sdk/fwd.h" namespace rocprofiler { @@ -128,6 +134,75 @@ perform_reduction(ReduceOperation reduce_op, std::vector* +perform_selection(std::map& dimension_map, + std::vector* input_array) +{ + if(input_array->empty()) return input_array; + for(auto& dim_pair : dimension_map) + { + int64_t encoded_dim_values = get_int_encoded_dimensions_from_string(dim_pair.second); + size_t bit_length = DIM_BIT_LENGTH / ROCPROFILER_DIMENSION_LAST; + int64_t mask = (MAX_64 >> (64 - bit_length)) << ((dim_pair.first - 1) * bit_length); + + input_array->erase(std::remove_if(input_array->begin(), + input_array->end(), + [&](rocprofiler_record_counter_t& rec) { + bool should_remove = + (encoded_dim_values & + (1 << rocprofiler::counters::rec_to_dim_pos( + rec.id, dim_pair.first))) == 0; + if(!should_remove) + { + rec.id = rec.id | mask; + rec.id = rec.id ^ mask; + } + return should_remove; + }), + input_array->end()); + } + + return input_array; +} + } // namespace const std::unordered_map& @@ -214,6 +289,7 @@ EvaluateAST::EvaluateAST(rocprofiler_counter_id_t out_id, , _reduce_op(get_reduce_op_type_from_string(ast.reduce_op)) , _agent(std::move(agent)) , _reduce_dimension_set(ast.reduce_dimension_set) +, _select_dimension_map(ast.select_dimension_map) , _out_id(out_id) { if(_type == NodeType::REFERENCE_NODE || _type == NodeType::ACCUMULATE_NODE) @@ -308,7 +384,25 @@ EvaluateAST::set_dimensions() break; case SELECT_NODE: { - // TODO: future scope + auto first = _children[0].set_dimensions(); + first.erase(std::remove_if(first.begin(), + first.end(), + [&](const MetricDimension& dim) { + return _select_dimension_map.find(dim.type()) != + _select_dimension_map.end(); + }), + first.end()); + if(first.empty()) + { + _dimension_types = std::vector{ + {dimension_map().at(ROCPROFILER_DIMENSION_INSTANCE), + 1, + ROCPROFILER_DIMENSION_INSTANCE}}; + } + else + { + _dimension_types = first; + } } break; } @@ -675,8 +769,11 @@ EvaluateAST::evaluate( static_cast(_reduce_op))); return perform_reduction(_reduce_op, result); } - // Currently unsupported - case SELECT_NODE: break; + case SELECT_NODE: + { + auto* result = _children.at(0).evaluate(results_map, cache); + return perform_selection(_select_dimension_map, result); + } } return nullptr; diff --git a/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/counters/evaluate_ast.hpp b/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/counters/evaluate_ast.hpp index 7f9b2625bc..881915222a 100644 --- a/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/counters/evaluate_ast.hpp +++ b/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/counters/evaluate_ast.hpp @@ -27,6 +27,7 @@ #include "lib/rocprofiler-sdk/aql/packet_construct.hpp" #include "lib/rocprofiler-sdk/counters/dimensions.hpp" +#include "lib/rocprofiler-sdk/counters/id_decode.hpp" #include "lib/rocprofiler-sdk/counters/metrics.hpp" #include "lib/rocprofiler-sdk/counters/parser/raw_ast.hpp" @@ -166,17 +167,18 @@ public: const rocprofiler_counter_id_t& out_id() const { return _out_id; } private: - NodeType _type{NONE}; - ReduceOperation _reduce_op{REDUCE_NONE}; - Metric _metric; - double _raw_value{0}; - std::vector _children; - std::string _agent; - std::vector _dimension_types{}; - std::vector _static_value; - std::unordered_set _reduce_dimension_set; - bool _expanded{false}; - rocprofiler_counter_id_t _out_id{.handle = 0}; + NodeType _type{NONE}; + ReduceOperation _reduce_op{REDUCE_NONE}; + Metric _metric; + double _raw_value{0}; + std::vector _children; + std::string _agent; + std::vector _dimension_types{}; + std::vector _static_value; + std::unordered_set _reduce_dimension_set; + std::map _select_dimension_map; + bool _expanded{false}; + rocprofiler_counter_id_t _out_id{.handle = 0}; }; using EvaluateASTMap = std::unordered_map; diff --git a/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/counters/tests/evaluate_ast_test.cpp b/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/counters/tests/evaluate_ast_test.cpp index 67176b911c..a602a20ddb 100644 --- a/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/counters/tests/evaluate_ast_test.cpp +++ b/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/counters/tests/evaluate_ast_test.cpp @@ -23,13 +23,16 @@ #include #include #include +#include #include +#include #include #include #include "lib/rocprofiler-sdk/agent.hpp" #include "lib/rocprofiler-sdk/counters/evaluate_ast.hpp" +#include "lib/rocprofiler-sdk/counters/id_decode.hpp" #include "lib/rocprofiler-sdk/counters/parser/reader.hpp" namespace @@ -364,6 +367,7 @@ construct_test_data_dim( record.counter_value = static_cast(rand()) / (static_cast(RAND_MAX / 50000)) + 1.0; auto recursive_dim = construct_test_data_dim(record.id, dims, dim_size); + if(!dims.empty()) ret.pop_back(); ret.insert(ret.end(), recursive_dim.begin(), recursive_dim.end()); } return ret; @@ -1233,3 +1237,132 @@ TEST(evaluate_ast, derived_counter_reduction) } } } + +TEST(evatuate_ast, evaluate_select) +{ + using namespace rocprofiler::counters; + + auto get_base_rec_id = [](uint64_t counter_id) { + rocprofiler_counter_instance_id_t base_id = 0; + set_counter_in_rec(base_id, {.handle = counter_id}); + return base_id; + }; + + auto select_dim = + [](auto a, + std::unordered_map> dims) -> auto + { + if(a.empty()) return a; + for(auto& dim_pair : dims) + { + a.erase(std::remove_if(a.begin(), + a.end(), + [&](rocprofiler_record_counter_t rec) { + return std::find(dim_pair.second.begin(), + dim_pair.second.end(), + rec_to_dim_pos(rec.id, dim_pair.first)) == + dim_pair.second.end(); + }), + a.end()); + } + for(auto& dim_pair : dims) + { + size_t bit_length = DIM_BIT_LENGTH / ROCPROFILER_DIMENSION_LAST; + int64_t mask = (MAX_64 >> (64 - bit_length)) << ((dim_pair.first - 1) * bit_length); + for(auto& rec : a) + { + rec.id = rec.id | mask; + rec.id = rec.id ^ mask; + } + } + return a; + }; + + std::unordered_map metrics = { + {"VOORHEES", Metric("gfx9", "VOORHEES", "a", "a", "a", "", "", 0)}, + {"KRUEGER", Metric("gfx9", "KRUEGER", "a", "a", "a", "", "", 1)}, + {"MYERS", Metric("gfx9", "MYERS", "a", "a", "a", "", "", 2)}, + {"BATES", + Metric("gfx9", + "BATES", + "C", + "C", + "C", + "select(VOORHEES+KRUEGER,[DIMENSION_XCC=[0]])", + "", + 3)}, + {"KRAMER", + Metric("gfx9", + "KRAMER", + "C", + "C", + "C", + "select(MYERS,[DIMENSION_XCC=[1],DIMENSION_SHADER_ARRAY=[0]])", + "", + 4)}, + }; + + std::unordered_map> base_counter_data = { + {"VOORHEES", construct_test_data_dim(get_base_rec_id(0), {ROCPROFILER_DIMENSION_XCC}, 8)}, + {"KRUEGER", construct_test_data_dim(get_base_rec_id(1), {ROCPROFILER_DIMENSION_XCC}, 8)}, + {"MYERS", + construct_test_data_dim(get_base_rec_id(2), + {ROCPROFILER_DIMENSION_XCC, ROCPROFILER_DIMENSION_SHADER_ARRAY}, + 8)}}; + + std::unordered_map> asts; + for(const auto& [val, metric] : metrics) + { + RawAST* ast = nullptr; + auto buf = yy_scan_string(metric.expression().empty() ? metric.name().c_str() + : metric.expression().c_str()); + yyparse(&ast); + ASSERT_TRUE(ast) << metric.expression() << " " << metric.name(); + asts.emplace("gfx9", std::unordered_map{}) + .first->second.emplace(val, + EvaluateAST({.handle = metric.id()}, metrics, *ast, "gfx9")); + yy_delete_buffer(buf); + delete ast; + } + + std::vector, int64_t>> + derived_counters = { + {"BATES", + select_dim(plus_vec(base_counter_data["VOORHEES"], base_counter_data["KRUEGER"]), + {{ROCPROFILER_DIMENSION_XCC, {0}}}), + 2}, + {"KRAMER", + select_dim( + base_counter_data["MYERS"], + {{ROCPROFILER_DIMENSION_XCC, {1}}, {ROCPROFILER_DIMENSION_SHADER_ARRAY, {0}}}), + 1}, + }; + std::unordered_map> base_counter_decode; + for(const auto& [name, base_counter_v] : base_counter_data) + { + base_counter_decode[metrics[name].id()] = base_counter_v; + } + + for(auto& [name, expected, eval_count] : derived_counters) + { + ROCP_INFO << name; + auto eval_counters = + rocprofiler::counters::get_required_hardware_counters(asts, "gfx9", metrics[name]); + ASSERT_TRUE(eval_counters); + ASSERT_EQ(eval_counters->size(), eval_count); + std::vector>> cache; + asts.at("gfx9").at(name).expand_derived(asts.at("gfx9")); + auto ret = asts.at("gfx9").at(name).evaluate(base_counter_decode, cache); + EXPECT_EQ(ret->size(), expected.size()); + int pos = 0; + asts.at("gfx9").at(name).set_out_id(*ret); + for(const auto& v : *ret) + { + set_counter_in_rec(expected[pos].id, {.handle = metrics[name].id()}); + EXPECT_EQ(v.id, expected[pos].id); + EXPECT_FLOAT_EQ(v.counter_value, expected[pos].counter_value); + pos++; + } + } +}